代码审计-PHP无框架项目SQL注入挖掘技巧

QQ截图20220401150247.jpg

相关原理分析要求

  1. 教学计划:审计项目漏洞 Demo->审计思路->完整源码框架->验证并利用漏洞
  2. 教学内容:PHP,JAVA 网站应用,引入框架类开发源码,相关审计工具及插件使用
  3. 必备知识点:环境安装搭建使用,相关工具插件安装使用,掌握前期各种漏洞原理及利用
  4. 开始前准备:审计目标的程序名,版本,当前环境(系统,中间件,脚本语言等信息),各种插件等
  5. 挖掘漏洞根本:可控变量及特定函数,不存在过滤或过滤不严谨存在绕过导致的安全漏洞

简易 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";
}

?>

QQ截图20220401152453.jpg

定点挖掘关键字总结

  • 可控变量,变量接受get,post,request传参(这里即可以是数据库查询的id,切换用户的uid,也可以是切换的文件filename(文件下载,文件包含,文件删除等等),也可以是网页翻页的页码等等(这里通常是base64加密,或者以XML格式,wsdl传输类型等等,或者需要抓包才能发现)
  • 特定函数:输出print,echo;数据库操作;代码/命令执行;文件包含/下载/删除等等
  • 代码审计方法:搜索特定的关键字寻找特定的漏洞,如搜索echo寻找XSS漏洞,搜索eval寻找代码执行漏洞

定点挖掘功能点总结

  • 如果我需要挖掘文件上传漏洞(会员中心,个人头像设置)的功能位置
  • 抓包分析找到源码中特定的文件代码段,进行文件上传代码段挖掘
  • 在挖掘SQL注入,进行数据库监控,监控当前页面和数据库交互过程(当前页面刷新执行的SQL语句)
  • 断点调试:访问页面对应代码进行断点调试(执行过程的先后顺序)

QQ业务图标点亮系统挖掘-数据库监控追踪

QQ截图20220401155126.jpg

查找关键字select(全局搜索),这里没有搜索到单纯的select关键字,而是将select封装成类名的形式,或者写入函数(所以有些搜索不到)

QQ截图20220401160219.jpg

注意不要区分大小写,这里要筛选的是传递的参数是变量的语句,也就是不要写死了的查询语句

QQ截图20220401160238.jpg

含有变量的查询语句是以下三条

QQ截图20220401160254.jpg

点击查看(这里进行数据的查询语句,并且sj函数返回的值为mysql_fetch_array()mysql_fetch_row()的扩展版本。除了将数据以数字索引方式储存在数组中之外,还可以将数据作为关联索引储存,用字段名作为键名。这里的function.php全部是定义的函数方法的集合,本身并没有调用函数

QQ截图20220401160325.jpg

ywX进行全局搜索,看在哪里调用这个函数(这里有两个文件调用了,在function.phpv144.php,function.php就是刚才的文件,可以先不看,点击调用了函数又传参的)

QQ截图20220401160715.jpg

这里是通过判断get的id差数据表,然后返回的值来执行相应的步骤

QQ截图20220401160735.jpg

网页访问v144.php,发现不能直接访问,应该有验证

QQ截图20220401160750.jpg

发现验证代码(这里是检验的代码)

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)

QQ截图20220401160903.jpg

修改logo的超链接(点击淡然点图标系统就会跳转目的网站)(这里抓包修改referer也可以,这里的跳转不是原网站的直接跳转,而是点击原网站的超链接才会有referer的记录).如果要用SQLmap跑的话,需要自定义数据包的header中的referer

QQ截图20220401160932.jpg

现在可以访问,只是提醒输入参数

QQ截图20220401160944.jpg

根据源代码分析,构造传参的值:api=ok&id=1&p=1&u=1

QQ截图20220401163109.jpg

发现SQL语句被执行(而且yWx($ID)函数被执行了三次),而且id是变量,因此存在注入点

QQ截图20220401163123.jpg

进一步查看(这里是无回显的注入,可以测试盲注),使用延迟来测试(应为被执行了三次,延迟了十多秒,可以确认存在注入点)

QQ截图20220401163200.jpg

74CMS人才招聘系统挖掘-2次注入应用功能(自带转义)

QQ截图20220402103723.jpg

  • 过滤机制查找(一般在common的文件中,应为每个传参的地方都需要引用)
  • 这里在include/common.inc.php文件中,都使用了addslashes_deep过滤
  • 传统的过滤函数addslashes()返回在预定义字符之前添加反斜杠的字符串

QQ截图20220402103801.jpg

addslashes_deep过滤,回调函数addslashes时,只对数据的值进行转义,所以如果使用者在此过程中引用数组的键进行特定处理时,存在$key注入风险。addslashes_deep函数,使其同时对键值进行转义,或者使用时明确不引用键内容。

QQ截图20220402103840.jpg

随意打开,都发现包含common.inc.php文件,只要传参,都会有过滤(不为空,转义)

QQ截图20220402103922.jpg

addslashes_deep函数,先判断不为空 array_map():返回数组为array每个元素应用callback函数之后的数组。 再判断魔术引号开没开,如果没打开,就用addslashes过滤,在套用mystrip_tags过滤一次 如果开了,就直接调用strip_tags()函数

QQ截图20220402104104.jpg

mystrip_tags函数的过滤(替代关键字) strip_tags()函数尝试返回给定的字符串 str 去除空字符、HTML 和 PHP 标记后的结果。它使用与函数 fgetss() 一样的机制去除标记。

QQ截图20220402104128.jpg

如果魔术引号开启,这里就变成了绕过魔术引号的注入,如:宽字节注入,二次注入等等 二次注入原理(条件:必须要insert和update) 注册用户:insert xiaodi union select’,过滤xiaodi union select /’,进入数据库还原为xiaodi union select’来绕过转义注入和魔术引号 修改用户:update xiaod union select’

QQ截图20220402104551.jpg

  • 进入网站的会员中心(才可能有insert和update个人信息)

根据个人中心的功能点,发现可能存在二次注入有两个地方 一是创建建立和更新建立;二是创建账号和修改个人资料,但是个人资料只能修改密码无法修改用户名,因此排除2选择1

QQ截图20220402104629.jpg

开启MySQL审计,填写建立的基本信息后查看

QQ截图20220402104647.jpg

查看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,而且是以十六进制传输

QQ截图20220402104727.jpg

QQ截图20220402104737.jpg

第三步技能特长是执行的更新操作

QQ截图20220402104937.jpg

第四步,发现插入了数据,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', '??')

QQ截图20220402105009.jpg

在下面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不是这里吧,这插入和更新的表名都不一样啊

QQ截图20220402105054.jpg

  • 在修改教育建立这里构造payload
aa','fullname'=user()#

QQ截图20220402105128.jpg

这里跟新了表(发现添加了转义字符)

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'

QQ截图20220402105218.jpg

但是下面的转义字符去掉了

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()显示数据库的用户

QQ截图20220402105245.jpg

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一步成功

QQ截图20220402105506.jpg

根据创建教育经历的url的关键字查找,这里全局搜索make4

  • http://127.0.0.1:9999/user/personal/personal_resume.php?act=make4&pid=6

QQ截图20220402105525.jpg

发现插入表resume_education的操作

QQ截图20220402105614.jpg

发现更新表resume_education的操作

QQ截图20220402105624.jpg

具体的insert函数的用法

QQ截图20220402105645.jpg

资源