代码审计-PHP无框架项目SQL注入挖掘技巧
相关原理分析要求
- 教学计划:审计项目漏洞 Demo->审计思路->完整源码框架->验证并利用漏洞
- 教学内容:PHP,JAVA 网站应用,引入框架类开发源码,相关审计工具及插件使用
- 必备知识点:环境安装搭建使用,相关工具插件安装使用,掌握前期各种漏洞原理及利用
- 开始前准备:审计目标的程序名,版本,当前环境(系统,中间件,脚本语言等信息),各种插件等
- 挖掘漏洞根本:可控变量及特定函数,不存在过滤或过滤不严谨存在绕过导致的安全漏洞
简易 SQL 注入代码段分析挖掘思路(SQL靶场的第二关)
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if (isset($_GET['id'])) {
$id = $_GET['id'];
//logging the connection parameters to a file for analysis.
$fp = fopen('result.txt', 'a');
fwrite($fp, 'ID:' . $id . "\n");
fclose($fp);
// connectivity
$sql = "SELECT * FROM users WHERE id=$id LIMIT 0,1";
$result = mysqli_query($con, $sql);
$row = mysqli_fetch_array($result);
if ($row) {
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:' . $row['username'];
echo "<br>";
echo 'Your Password:' . $row['password'];
echo "</font>";
} else {
echo '<font color= "#FFFF00">';
print_r(mysqli_error($con));
echo "</font>";
}
} else {
echo "Please input the ID as parameter with numeric value";
}
?>
定点挖掘关键字总结
- 可控变量,变量接受
get
,post
,request
传参(这里即可以是数据库查询的id,切换用户的uid,也可以是切换的文件filename(文件下载,文件包含,文件删除等等),也可以是网页翻页的页码等等(这里通常是base64加密,或者以XML格式,wsdl传输类型等等,或者需要抓包才能发现) - 特定函数:输出
print
,echo
;数据库操作;代码/命令执行;文件包含/下载/删除等等 - 代码审计方法:搜索特定的关键字寻找特定的漏洞,如搜索echo寻找XSS漏洞,搜索eval寻找代码执行漏洞
定点挖掘功能点总结
- 如果我需要挖掘文件上传漏洞(会员中心,个人头像设置)的功能位置
- 抓包分析找到源码中特定的文件代码段,进行文件上传代码段挖掘
- 在挖掘SQL注入,进行数据库监控,监控当前页面和数据库交互过程(当前页面刷新执行的SQL语句)
- 断点调试:访问页面对应代码进行断点调试(执行过程的先后顺序)
QQ业务图标点亮系统挖掘-数据库监控追踪
查找关键字select(全局搜索),这里没有搜索到单纯的select关键字,而是将select封装成类名的形式,或者写入函数(所以有些搜索不到)
注意不要区分大小写,这里要筛选的是传递的参数是变量的语句,也就是不要写死了的查询语句
含有变量的查询语句是以下三条
点击查看(这里进行数据的查询语句,并且sj函数返回的值为
mysql_fetch_array()
是mysql_fetch_row()
的扩展版本。除了将数据以数字索引方式储存在数组中之外,还可以将数据作为关联索引储存,用字段名作为键名。这里的function.php
全部是定义的函数方法的集合,本身并没有调用函数
对
ywX
进行全局搜索,看在哪里调用这个函数(这里有两个文件调用了,在function.php
和v144.php
,function.php
就是刚才的文件,可以先不看,点击调用了函数又传参的)
这里是通过判断get的
id
差数据表,然后返回的值来执行相应的步骤
网页访问
v144.php
,发现不能直接访问,应该有验证
发现验证代码(这里是检验的代码)
in_array()
函数搜索数组中是否存在指定的值,查询域名是否在sohuquan里面。$_SERVER['HTTP_HOST']
为获取当前访问的域名,array()
是创建一个数组$_SERVER["HTTP_REFERER"]
获取来源的网站,这里也就是说,如果来源的网站不是在这个HTTP_HOST域名内,就不允许访问.这里是取的url的/
分隔成数组去掉http://
的第一部分,如http://127.0.0.1:8888/php/v144.php
,就是127.0.0.1:8888
(但是很奇怪直接从网站主页访问不行,我猜测是数据包内没有referer)
修改logo的超链接(点击淡然点图标系统就会跳转目的网站)(这里抓包修改referer也可以,这里的跳转不是原网站的直接跳转,而是点击原网站的超链接才会有referer的记录).如果要用SQLmap跑的话,需要自定义数据包的header中的referer
现在可以访问,只是提醒输入参数
根据源代码分析,构造传参的值:
api=ok&id=1&p=1&u=1
发现SQL语句被执行(而且
yWx($ID)
函数被执行了三次),而且id是变量,因此存在注入点
进一步查看(这里是无回显的注入,可以测试盲注),使用延迟来测试(应为被执行了三次,延迟了十多秒,可以确认存在注入点)
74CMS人才招聘系统挖掘-2次注入应用功能(自带转义)
- 过滤机制查找(一般在common的文件中,应为每个传参的地方都需要引用)
- 这里在
include/common.inc.php
文件中,都使用了addslashes_deep
过滤 - 传统的过滤函数
addslashes()
返回在预定义字符之前添加反斜杠的字符串
addslashes_deep过滤,回调函数addslashes时,只对数据的值进行转义,所以如果使用者在此过程中引用数组的键进行特定处理时,存在$key注入风险。addslashes_deep函数,使其同时对键值进行转义,或者使用时明确不引用键内容。
随意打开,都发现包含common.inc.php文件,只要传参,都会有过滤(不为空,转义)
addslashes_deep
函数,先判断不为空array_map()
:返回数组为array每个元素应用callback函数之后的数组。 再判断魔术引号开没开,如果没打开,就用addslashes
过滤,在套用mystrip_tags
过滤一次 如果开了,就直接调用strip_tags()
函数
mystrip_tags
函数的过滤(替代关键字)strip_tags()
函数尝试返回给定的字符串 str 去除空字符、HTML 和 PHP 标记后的结果。它使用与函数fgetss()
一样的机制去除标记。
如果魔术引号开启,这里就变成了绕过魔术引号的注入,如:宽字节注入,二次注入等等 二次注入原理(条件:必须要insert和update) 注册用户:
insert xiaodi union select’
,过滤xiaodi union select /’
,进入数据库还原为xiaodi union select’
来绕过转义注入和魔术引号 修改用户:update xiaod union select’
- 进入网站的会员中心(才可能有insert和update个人信息)
根据个人中心的功能点,发现可能存在二次注入有两个地方 一是创建建立和更新建立;二是创建账号和修改个人资料,但是个人资料只能修改密码无法修改用户名,因此排除2选择1
开启MySQL审计,填写建立的基本信息后查看
查看insert的语句,但是这里的xiaodi是用户名,真正自己输入的数据没有插入进去 这里只有电话号码,但是大概率电话号码做了数字型的限制,无法构造字符串,因此再往下看看
2022/1/22 Їƚy 22:46
INSERT INTO qs_members_log (log_uid,log_username,log_utype,log_type,log_addtime,log_ip,log_address,log_value) VALUES ( '1','xiaodi','2','1105', '1642862794','127.0.0.1','LAN','\xD0?\xC4\xC1?\xF2\xC0\xFA(\xCE?\xAE\xB5\xCF)')
第二步的插入都是选项(在数据库里面都是数字型的),无法构造 唯一的一个最近工作的职位,是update,而且是以十六进制传输
第三步技能特长是执行的更新操作
第四步,发现插入了数据,xiaodi和woaixiaodi都插入了
2022/1/22 Їƚy 23:07
INSERT INTO qs_resume_education (`uid`, `pid`, `start`, `endtime`, `school`, `speciality`, `education`, `education_cn`) VALUES ('1', '2', '2001\xC4\xEA2\xD4\xC2', '2027\xC4\xEA2\xD4\xC2', 'xiaodi', 'woaixiaodi', '71', '??')
在下面update里面也有小迪
2022/1/22 Їƚy 23:07
UPDATE qs_resume SET `photo`='0', `complete`='1', `complete_percent`='60', `key`='xiaodi \xCF\xEE?\xBE\xAD\xC0\xED/\xB2\xFA?\xBE\xAD\xC0\xED \xB5\xCF00 \xCF\xEE?00 \xCF\xEE?\xBE\xAD\xC0\xED \xBE\xAD\xC0\xED00 \xB2\xFA?00 \xB2\xFA?\xBE\xAD\xC0\xED ??00 woaixiaodi', `refreshtime`='1642864044' WHERE uid='1' AND id='2'
我感觉update不是这里吧,这插入和更新的表名都不一样啊
- 在修改教育建立这里构造payload
aa','fullname'=user()#
这里跟新了表(发现添加了转义字符)
UPDATE qs_resume_education SET `start`='2001\xC4\xEA2\xD4\xC2', `endtime`='2027\xC4\xEA2\xD4\xC2', `school`='aa\',\'fullname\'=user()#', `speciality`='aa\',\'fullname\'=user(', `education`='71', `education_cn`='??' WHERE id='1' AND uid='1'
但是下面的转义字符去掉了
2022/1/22 Їƚy 23:22
UPDATE qs_resume SET `photo`='0', `complete`='1', `complete_percent`='60', `key`='aa','fullname'=user()# \xCF\xEE?\xBE\xAD\xC0\xED/\xB2\xFA?\xBE\xAD\xC0\xED \xB5\xCF00 \xCF\xEE?00 \xCF\xEE?\xBE\xAD\xC0\xED \xBE\xAD\xC0\xED00 \xB2\xFA?00 \xB2\xFA?\xBE\xAD\xC0\xED ??00 aa','fullname'=user(', `refreshtime`='1642864966' WHERE uid='1' AND id='2'
注入的原理:通过update将用户名改为user()显示数据库的用户
Error:Query error:UPDATE qs_resume SET `photo`='0', `complete`='1', `complete_percent`='60', `key`='aa','fullname'=user()# 项目经理/产品经理 小迪00 项目00 项目经理 经理00 产品00 产品经理 硕士00 aa','fullname'=user(', `refreshtime`='1642864966' WHERE uid='1' AND id='2'
上网查了下别人的记录,并且再次尝试看
aa','fullname'=user()#
成功,这里需要多试几次才行,我刚开始报错了没成功,后来复制网上的payload一步成功
根据创建教育经历的url的关键字查找,这里全局搜索make4
http://127.0.0.1:9999/user/personal/personal_resume.php?act=make4&pid=6
发现插入表resume_education的操作
发现更新表resume_education的操作
具体的insert函数的用法
0 条评论