当前位置: 首页 > 科技观察

PHP代码审计就是这么好学,由浅入深

时间:2023-03-17 20:15:03 科技观察

以Emlog6.0beta版为指导,一篇关于PHP语言CMS代码审计的文章,详细记录了代码审计的完整过程。学习代码审计,不妨从本文开始。仔细看完,相信你一定有所收获!前言文章基本上记录了作者对EmlogCMS的审计过程,看似繁琐,但代码审计的过程就是这样的。找到可能的项目,然后仔细构建以验证。我们会遇到很多阻碍,坚持测试,思维活跃一些,基本就会有所收获。真心希望后来者能耐心看完,当然最好能受到启发。大家需要注意的一点是,代码审计是为了学习和避免SDL中类似的错误,也是为了帮助开源系统修复相关问题,而不是为了得到一些0day~0x00Emlog6.0betaEMLOG6.0官网地址:https://www.emlog.net/Emlog6.0测试版下载地址:https://www.emlog.net/download由于官方限制论坛会员(注册付费)只能下载,这里提供一个原始下载地址:https://www.lanzous.com/i1l5gad文件验证:文件:C:\Users\stdy\Desktop\emlog_6.0.0.zip大小:607725字节修改时间:2018-08-0620:53:50MD5:7844FE6FEAE7AF68052DC878B8811FACSHA1:E06A050D2A0AA879DB7F349'2Blog3E0AA879DB7F349sblog在这个博客系统上。其实圈内很多大佬都在用,只是这个CMS没有审核文章。笔者将此CMS作为PHP代码审核的收官之作。0x01初步测试首先,我们要先安装!安装成功后首页界面:安装成功默认后台登录地址:./admin/登录成功后:后台界面闲话,感觉6.0版比5.3.1版好多了~安装完之后,大家应该多搜集一下相关信息这个CMS尽可能多,这将对我们审核代码有很大帮助。因此,分析了该CMS的总体结构。Emlog是一种MVC设计模式。总体结构如图:emlog结构。因此,我们主要分析admin和include文件夹下的文件。数据库表:DATABASE在根目录下的init.php文件中。错误级别指定为7:0x02使用漏洞扫描器,可能有朋友会问为什么要用“漏扫”?不是代码审计吗?这里需要纠正一下这个观点,missscanning其实就是一个自动化的黑盒测试。在本地环境中,我们不会影响任何业务。通过漏扫发现的漏洞可以方便我们快速定位漏洞位置。这是一种高效的方式,这也是团队成员通过漏扫获取了百度多个高危漏洞给笔者的启示。这里使用了重型扫描仪AWVS,报告如下:结果是在本地扫描时,使用了XAMPPwindows10PHP5.6的环境,所以漏洞报告中存在很多误报。missedscan主要是扫描了几个XSS漏洞和CSRF漏洞,所以我们先对这两类漏洞进行验证。0x03文章编辑器存储XSS在后台编辑器,编辑文章./admin/admin_log.php编辑器XSS发布成功后,进入首页emlogXSS进入文章页面弹出后文章页面的XSS。这里你可能会说不能用,但是emlog设计了一个member/author功能。在emlog的一些模板中,可以在前台注册会员。会员登录后可以编辑、发表文章、评论等。Emlog官方还提供了文章投稿插件,调用官方默认的Kindeditor编辑器。这个编辑器有它自己的HTML编辑模式。即使没有这种模式,攻击者仍然可以抓包修改来达到攻击的目的。为什么前台不过滤?为了支持文章的HTML代码输出,kindeditor保存的输出内容没有转义。emlog会员/投稿修复建议:参考其他CMS做好文章内容关键词检测,做好过滤或转义0x04UploadifySWFXSSEmlog使用uploadify.swf上传文件,文件路径为/include/lib/js/uploadify/uploadify.swf构造Payload:http://www.test.com//include/lib/js/uploadify/uploadify.swf?uploadifyID=00%22%29%29;}catch%28e%29{alert%281%29;}//%28%22&movieName=%22])}catch(e){if(!window.x){window.x=1;alert(document.cookie)}}//&.swf效果,Browserfilter可以忽略:SWFXSS0x05ReflectiveXSS这里的XSS主要发生在cookie上,因为admin/admin_log、admin/sort.php、admin/link.php等页面需要添加隐藏表单中属性中的token值,而这个token值直接从用户的cookie中获取,导致反射型XSS拦截抓包修改cookie中的token值如下:payloadeffect:COOKIEXSS二次验证CSRF漏洞lity,这是前台的搜索框CSRF根本没有任何价值,然后管理员添加的友情链接的XSS经验证不存在,后台功能会限制字符数。然后我们开始了原来的代码审计工作,主要是借用了seay代码审计工具和Rips,这种审计工具主要是通过正则匹配php中可能导致危险的函数来判断可能存在的漏洞。半自动化的方式在一定程度上减轻了代码审计的压力。0x06基本函数首先看了一下文件操作相关的函数,发现经常用到View::getView这个方法。在include/lib/view.php文件中,源码如下:deleteLog($val);doAction('del_log',$val);}$CACHE->updateCache();if($pid=='draft'){emDirect("./admin_log.php?pid=draft&active_del=1");}else{emDirect("./admin_log.php?active_del=1");}break;case'top':foreach($logsas$val){$Log_Model->updateLog(array('top'=>'y'),$val);}emDirect("./admin_log.php?active_up=1");break;case'sortop':foreach($logsas$val){$Log_Model->updateLog(array('sortop'=>'y'),$val);}emDirect("./admin_log.php?active_up=1");break;case'notop':foreach($logsas$val){$Log_Model->updateLog(array('top'=>'n','sortop'=>'n'),$val);}emDirect("./admin_log.php?active_down=1");break;case'hide':foreach($logsas$val){$Log_Model->hideSwitch($val,'y');}$CACHE->updateCache();emDirect("./admin_log.php?active_hide=1");break;...//中间代码需要验证管理身份,所以省略case'uncheck':if(ROLE!=ROLE_ADMIN){emMsg('Insufficientauthority!','./');}$Log_Model->checkSwitch($gid,'n');$CACHE->updateCache();emDirect("./admin_log.php?active_unck=1");break;}}然后我们尝试删除未经允许的文章http://www.test.com/admin/admin_log.php?action=operate_log&operate=del&blog=29&token=994132a26661c8c244a91063c4701a7e失败,提示权限不足,来到\include\model\log_model.php发现/***删除文章**@paramint$blogId*/functiondeleteLog($blogId){$author=ROLE==ROLE_ADMIN?'':'andauthor='.UID;$this->db->query("DELETEFROM".DB_PREFIX."blogwheregid=$blogId$author");//这个上一句限制作者删除自己的文章if($this->db->affected_rows()<1){emMsg('Insufficientpermissions!','./');}//评论$this->db->query("DELETEFROM".DB_PREFIX."commentwheregid=$blogId");//标签$this->db->query("UPDATE".DB_PREFIX."tagSETgid=REPLACE(gid,',$blogId,',',')WHEREgidLIKE'%".$blogId."%'");$this->db->query("DELETEFROM".DB_PREFIX."tagWHEREgid=','");//附件$query=$this->db->query("selectfilepathfrom".DB_PREFIX."attachmentwhereblogoid=$blogId");while($attach=$this->db->fetch_array($query)){if(file_exists($attach['文件路径'])){$fpath=str_replace('thum-','',$attach['filepath']);if($fpath!=$attach['filepath']){@unlink($fpath);}@unlink($attach['filepath']);}}$this->db->query("DELETEFROM".DB_PREFIX."attachmentwhereblogid=$blogId");}这个未授权漏洞不存在,阅读下面函数判断也是类似的。到这里,我们已经熟悉了整个CMS的架构。基本上我们可以直接根据对应的功能函数手动找到对应的功能位置。遗憾的是,通过Rips代码审计工具得到的结果都没有成功复现...0x07Seayauxiliaryaudit相信很多人都知道mage的这个工具,主要是中文的,用起来方便,但是完全依靠正则的方法去匹配函数,只能找到那些函数的直接控制漏洞。逻辑上的漏洞有时可以通过逆向演绎来发现,但这种情况很少见。用这个工具扫描一共120种可能的情况(根据经验,98%以上是无法重现的),然后一一检查。有些,比如带有反单引号的SQL语句,很容易判断为忽略。,无需考虑。在/admin/store.php中看到这样一串代码:store.php在这里,我的想法是,如果emlog官网有URL跳转链接,那么就可以构建下载任意远程文件到网站,但是官网已经测试如果没有跳转链接,那么我们尝试下载其他插件(链接跳转等),或者黑客精心构造一个插件或者模板,然后使用。这也是一个可行的方案。这里需要管理员权限。作为代码审计的参考思路,不是找什么0day,而是希望大家在代码审计中有所收获。(1).SQL注入对于SQL注入,Seay工具从来都不准确。这里笔者推荐的方法是使用全局搜索$_GET[或者$_PSOT[,然后检查SQL查询是否被代入,然后一一验证。然后在没有过滤IP参数的情况下发现了这样一个IP参数,然后去admin/comment.php查看comment.php再看delCommentByIp($ip)函数IP参数sql,就可以判断是否存在SQL注入。验证如下:SQL注入(2)。一个CSRF+任意文件分析后删除$_GET[]类型,然后寻找$_POST[],然后在admin/data.php文件中找到如下代码data.php。这里发现没有验证toknen,那么可以构造一个csrf页面,笔者这里就不演示了,直接BURP验证删除任意文件,关于CSRF,只要提到LoginAuth::checkToken()方法即可在上面的基本函数部分没有调用,有CSRFCSRF+任意删除文件(3)到这里就成功删除了。TAGSQL注入发现这里没有过滤的POST参数。同时,在deleteTag()函数中,代入了SQL查询,所以又是一个SQL注入标签sql,看deleteTag()函数:deletetag调用了getBlogIdsFromTagId()函数,同样没有过滤getBlogIdsFromTagId,所以使用packetcapturetoverify:验证,但使用时不回显其他语句。不知道是什么原因,也没有仔细探索过,但是可以使用盲时间注入的方式。至此,使用工具的半自动化审计就结束了。接下来,我们将准备进行手动测试。0x08手动测试手动测试不是简单的翻文件,应该以灰盒测试为主,从逻辑、权限、敏感信息等入手。(1).背景登录时存在暴力破解风险这里,我之前提到的验证码没有及时销毁的历史问题依然存在。我不会在这里详细描述它。请参考https://blog.csdn.net/dyboy2017/article/details/78433748(2)。报错信息导致物理路径泄露。不要认为这是一件小事。当存在sql注入时,我们就有机会直接写shell文件了。这是一种安全且非同小可的低权限方法。游客条件下测试物理路径payload:http://www.test.com/admin/attachment.php?action[]=原因是:addslashes()expectsparameter1(3).Cookie可以计算在include/lib/loginauth.php从第134行开始/***Writecookieforloginverification**@paramint$user_idUserID*@parambool$rememberWhethertoremembertheuserornot*/publicstaticfunctionsetAuthCookie($user_login,$ispersis=false){if($ispersis){$expiration=time()+?0*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**@paramint$user_iduserlogin*@paramint$expirationCookieexpirationinseconds*@returnstringAuthenticationcookiecontents*/privatestaticfunctiongenerateAuthCookie($user_login,$expiration){$key=self::emHash($user_login.'|'.$expiration);$hash=hash_hmac('md5',$user_login.'|'.$expiration,$key);$cookie=$user_login.'|'.$expiration.'|'.$hash;return$cookie;}可以看到这里的cookie是可以直接计算的,只需要知道根目录下的config.php即可目录//authkeydefine('AUTH_KEY','dx1&CH^En86GZnxd9CLO7GwC0Q5eYHKM450f598bbd148b6a62f7d263623e31c3');//cookienamedefine('AUTH_COOKIE_NAME','EM_AUTHCOOKIE_VzfVniPWDqd1LM3BHFocn)(4).侧边栏存储型XSS也是为了支持输出HTML代码,相应的脚本代码标签没有进行转义,导致侧边栏存在存储型XSS。XSS0x09获取外壳(1)。SQL注入获取shell上面说了存在SQL注入,同时可以获取到物理路径,那么就可以直接写Shell(2)了。后台插件上传zip因为后台可以直接上传本地zip文件,这里我们去官网下载一个插件,同时把我们的shell文件(比如dyboy.php)添加到zip,上传安装这个插件,然后shell地址为:http://www.test.com/content/plugins/pluginname/dyboy.php(3).后台模板上传zip和插件原理一样,这里的shell地址是:http://www.test.com/content/templates/templatename/dyboy.php(4)。备份文件取shell后台的数据函数,先备份一个,然后下载到本地,在outfile'D:\\Server\\htdocs\\safe\\dyboy.php'中加入SELECT"";然后导入备份,恢复本地数据,于是在网站中生成了一个目录dyboy.php的shell0x0A总结EMLOG是一个非常小巧轻便的博客系统,占用资源极少,非常适合博主作为博客使用.其实只要不开启会员功能,没有弱口令就没有太大的威胁。本文用作PHP代码审计的起点。文中介绍的方法同样适用于其他CMS代码的审计分析。

猜你喜欢