浅析PHP代码审计中的SQL注入漏洞

news/2024/7/23 8:55:25 标签: php, sql, mysql

浅析PHP代码审计中的SQL注入漏洞

  • 1.概述
  • 2.普通注入
  • 3.编码注入
    • 宽字节注入
    • 二次urldecode注入
  • 4.漏洞防范
    • gpc/rutime魔术引号
    • 过滤函数和类
      • addslashes函数
      • mysql_[real_]escape_string函数
      • intval等字符转换
    • PDO prepare预编译

1.概述

SQL注入的攻击方式有下面几种:

  • 在权限较大的情况下,通过SQL注入可以直接写入webshell,或者直接执行系统命令等
  • 在权限较小的情况下,也可以通过注入来获得管理员的密码等信息,或者修改数据库内容进行一些钓鱼或者其他间接利用

登录页面的注入现在来说大多是发生在HTTP头里面的client-ipx-forward-for,一般用来记录登录的IP地址,另外在订单系统里面,由于订单涉及购物车等多个交互,所以经常会发生二次注入。我们在通读代码挖掘漏洞的时候可以着重关注这几个地方


2.普通注入

这里说的普通注入是指最容易利用的SQL注入漏洞,比如直接通过注入union查询就可以查询数据库,一般的SQL注入工具也能够非常好地利用。普通注入有int型和string型

数据库操作存在一些关键字,比如select from、mysql_connect、mysql_query、mysql_fetch_row等,数据库的查询方式还有update、insert、delete,我们在做白盒审计时,只需要查找这些关键字,即可定向挖掘SQL注入漏洞


3.编码注入

在SQL注入里,最常见的编码注入是MySQL宽字节以及urldecode/rawurldecode函数导致的

宽字节注入

在使用PHP连接MySQL的时候,当设置“set character_set_client=gbk”时会导致一个编码转换的注入问题,也就是我们所熟悉的宽字节注入

关于这个漏洞的解决方法推荐如下几种方法:

  1. 在执行查询之前先执行SET NAMES 'gbk',character_set_client=binary设置character_set_clientbinary
  2. 使用mysql_set_charset('gbk')设置编码,然后使用mysql_real_escape_string()函数被参数过滤
  3. 使用pdo方式,在PHP5.3.6及以下版本需要设setAttribute(PDO::ATTR_EMULATE_PREPARES,false);来禁用prepared statements的仿真效果

如上几种方法更推荐第一和第三种

对宽字节注入的挖掘方法也比较简单,只要搜索如下几个关键字即可:

php">SET NAMES
character_set_client=gbk
mysql_set_charset('gbk')

二次urldecode注入

如果某处使用了urldecode或者rawurldecode函数,则会导致二次解码生成单引号而引发注入。原理是我们提交参数到WebServer时,WebServer会自动解码一次,假设目标程序开启了GPC,我们提交/1.php?id=1%2527

因为我们提交的参数里面没有单引号,所以第一次解码后的结果是id=1%27(%25解码的结果是%)

如果程序里面使用了urldecode或者rawurldecode函数来解码id参数,则解码后的结果是id=1’成功出现引发注入

测试代码:

php"><?php
$a=addslashes($_GET['p']);
$b=urldecode($a);
echo '$a='.$a;
echo '<br />';
echo '$b='.$b;

在这里插入图片描述


4.漏洞防范

gpc/rutime魔术引号

magic_quotes_gpc负责对GET、POST、COOKIE的值进行过滤,magic_quotes_runtime对从数据库或者文件中获取的数据进行过滤。通常在开启这两个选项之后能防住部分SQL注入漏洞被利用

为什么说是部分,因为我们之前也介绍了,它们只对单引号(')、双引号(")、反斜杠(\)及空字符NULL进行过滤,在int型的注入上是没有多大作用的

过滤函数和类

addslashes函数

addslashes函数过滤的值范围和GPC是一样的,即单引号(')、双引号(")、反斜杠(\)及空字符NULL,它只是一个简单的检查参数的函数,大多数程序使用它是在程序的入口,进行判断如果没有开启GPC,则使用它对$_POST/$_GET等变量进行过滤,不过它的参数必须是string类型

sql_real_escape_string_84">mysql_[real_]escape_string函数

mysql_escape_stringmysql_real_escape_string函数都是对字符串进行过滤,在PHP4.0.3以上版本才存在,如下字符受影响【\x00】【\n】【\r】【\】【'】【"】【\x1a】,两个函数唯一不一样的地方在于mysql_real_escape_string接受的是一个连接句柄并根据当前字符集转义字符串,所以推荐使用mysql_real_escape_string

使用举例:

php"><?php
$con = mysql_connect("localhost", "root", "123456");
$id = mysql_real_escape_string($_GET['id'],$con);
$sql="select * from test where id='".$id."'";
echo $sql;

当请求该文件?id=1’时,上面代码输出:select*from test where id='1\''

intval等字符转换

intval的作用是将变量转换成int类型,这里举例intval是要表达一种方式,一种利用参数类型白名单的方式来防止漏洞,对应的还有很多如floatval

应用举例如下:

php"><?php
$id=intval("1 union select ");
echo $id;

以上代码输出:1

PDO prepare预编译

我们先来看一段代码:

php"><?php
dbh = new PDO("mysql:host=localhost; dbname=demo", "user", "pass");
$dbh-exec("set names 'gbk'");
$sql="select * from test where name = ? and password = ?";
$stmt = $dbh-prepare($sql);
$exeres = $stmt-execute(array($name, $pass));

上面这段代码虽然使用了pdo的prepare方式来处理sql查询,但是当PHP版本<5.3.6之前还是存在宽字节SQL注入漏洞,原因在于这样的查询方式是使用了PHP本地模拟prepare,再把完整的SQL语句发送给MySQL服务器,并且有使用set names 'gbk'语句,所以会有PHP和MySQL编码不一致的原因导致SQL注入,正确的写法应该是使用ATTR_EMULATE_PREPARES来禁用PHP本地模拟prepare,代码如下:

php"><?php
dbh = new PDO("mysql:host=localhost; dbname=demo", "user", "pass");
$dbh-setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh-exec("set names 'utf8'");
$sql="select * from test where name = ? and password = ?";
$stmt = $dbh-prepare($sql);
$exeres = $stmt-execute(array($name, $pass));

http://www.niftyadmin.cn/n/229841.html

相关文章

神经微分方程Resnet变体实现内存下降和保持精度

本文内容&#xff1a; 1、学习神经微分方程的笔记&#xff0c;主要锻炼自己学习新知识的能力和看有很多数学原理的论文能力&#xff1b; 2、神经微分方程可以用于时序数据建模、动力学建模等&#xff0c;但是本文专注于分类问题-resnet变体<比较容易理解>&#xff1b; …

“万物智联·共数未来”2023年移远通信物联网生态大会圆满落幕

4月12日&#xff0c;以“万物智联共数未来”为主题的2023年移远通信物联网生态大会在深圳前海华侨城JW万豪酒店隆重举办。 大会邀请到来自运营商、主流芯片商、行业客户、产业协会、标准联盟、媒体等产业链合作伙伴的40多位行业大咖&#xff0c;共话物联网产业的现在和未来。参…

nssctf web入门(4)

这里通过nssctf的题单web安全入门来写&#xff0c;会按照题单详细解释每题。题单在NSSCTF中。 想入门ctfweb的可以看这个系列&#xff0c;之后会一直出这个题单的解析&#xff0c;题目一共有28题&#xff0c;打算写10篇。 [ZJCTF 2019]NiZhuanSiWei [ZJCTF 2019]NiZhuanSiWei…

Git详细教程,彻底理解Git运作机制

Git详细教程前言git常用命令版本管理远程仓库分支管理正文git版本管理版本回退工作区和暂存区工作区版本库&#xff08;Repository&#xff09;撤销修改删除文件git远程仓库github使用添加远程库小结从远程库克隆git分支管理创建和合并分支git merge vs git rebase解决冲突第一…

[C++]类与对象下篇

目录 类与对象下篇&#xff1a;&#xff1a; 1.再谈构造函数 2.static成员 3.友元 4.内部类 5.匿名对象 6.拷贝对象时的编译器优化 7.再次理解封装 8.求12...n(不能使用乘除法、循环、条件判断) 9.计算日期到天数的转换 10.日期差值 11.打印日期 12.累加天数 类与对象下篇&…

Linux: 性能分析之内存增长和泄漏

文章目录1. 前言2. 背景3. 内存增长和泄漏分析方法3.1 跟踪 malloc(), free() 等接口3.1.1 用 perf 采样3.1.2 用 ebpf 来跟踪3.2 跟踪 brk() 调用3.2.1 使用 perf 跟踪 brk()3.2.2 使用 ebpf 跟踪 brk()3.3 跟踪 mmap() 调用3.3.1 使用 perf 跟踪 mmap()3.3.2 使用 ebpf 跟踪 …

查询练习:ANY 表示至少一个 - DESC ( 降序 )

查询课程 3-105 且成绩 至少 高于 3-245 的 score 表。 SELECT * FROM score WHERE c_no 3-105; --------------------- | s_no | c_no | degree | --------------------- | 101 | 3-105 | 90 | | 102 | 3-105 | 91 | | 103 | 3-105 | 92 | | 104 | 3-105 |…

centos里 C++项目 time() 和 gettimeofday() 返回不同的秒数

项目里有个地方获取时间戳需要比较精确&#xff0c;用了 gettimeofday()获取的 很多地方也引用了这里获取时间戳 struct timeval tv;gettimeofday( &tv, NULL );m_usec_time (utime_t) tv.tv_sec * 1000 * 1000 tv.tv_usec;m_time (time_t) tv.tv_sec; 而linux 下一般获…