sql注入漏洞中,常见的防护方案有哪些?
使用预处理语句
- 原理:SQL结构和数据分离,即使传入恶意字符串(比如, ' or 1=1;),数据库也会把他当作纯数据处理,不会执行。
输入验证和白名单
- 原理:在输入sql之前,严格校验其格式、类型或者取值范围。zzzzz
- 输入验证:严格检查类型
- 使用白名单匹配
特殊字符转义
- 对特殊字符进行转义(比如, ‘ “ \)使其失去语法意义。
最小权限原则
- 给数据库分配最小必要权限
类型转换
- 将输⼊强制转换为整数/浮点 ⽤于整数/浮点类型的输⼊参数处理 可防⽌SQL注⼊
针对常见的防护方案,哪些是可以绕过的?哪些又没法绕过?
特殊字符转义
- 使用addshalshes()函数对特殊字符转义
-
- 单引号
'→' - 双引号
"→" - 反斜杠 `` →
\ - NULL字符
\0→\0
- 单引号
- 绕过姿势
-
- 宽字节注入,使用%df可以绕过。
原始输入: %df'
addslashes: %df' (0xdf 0x5c 0x27)
GBK解码: 運' (0xdf5c=運, 0x27=单引号)
-
- 二次注入
-
-
- 原理:数据进入数据库之前被转义,从数据库取出后没有再次过滤直接拼接到sql语句中。
-
-
- 数字型注入
-
-
- 只转义引号,不影响数字
-
- 编解码绕过
-
- 注⼊语句进⾏两次编码,⾸先通过addslashes()过滤,然后urlencode解码
- 弱类型
-
- 在判断数据类型时,php有类型函数对其判断,php是⼀种弱类型,会⾃动转换类型。 如果只是判断并没有赋值。可能会造成漏洞。
- http头信息注入
-
- 通过 getenv()函数或者$_SERVER获取。
pikachu靶场,审计并利用宽字节注入漏洞
if(isset($_POST['submit']) && $_POST['name']!=null){
$name = escape($link,$_POST['name']); //对输入的数据进行转义
$query="select id,email from member where username='$name'";
$set = "set character_set_client=gbk"; //设置字符集为gbk
execute($link,$set);
$result=mysqli_query($link, $query);
if(mysqli_num_rows($result) >= 1){
while ($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>your uid:{$id} <br />your email is: {$email}</p>";
}
}else{
$html.="<p class='notice'>您输入的username不存在,请重新输入!</p>";
}
上述代码漏洞逻辑:
- 首先对输入的数据进行转义
- 设置字符集为gbk
- 导致宽字节注入漏洞
绕过方法:
// 使用 %df让转义符失效
$_POST['name'] = '%df' OR 1=1#";
// escape函数处理后
$name = '%df' OR 1=1#";
// 经过GBK编码解析:
// %df + \ → %df%5c合并成一个汉字 "運" (0xdf5c)
// 原本的转义符 \ 被"吃掉"了
// 最终SQL语句变为
$query = "select id,email from member where username='運' OR 1=1#'"; //单引号逃逸成功
验证:
命令注入漏洞常见的函数有哪些?
system()
- 自动输出命令执行结果
- 返回命令执行的最后一行
exec()
- 不会自动输出结果,需要使用echo才能显示
- 结果存储在数组中
shell_exec()
- 返回完整输出,以字符串的方式返回
passthru()
- 直接输出原始数据,有回显
- 适合传输二进制数据
- 不对数据做处理
pcntl_exec()
- Linux下面的扩展
- 在当前进程空间执⾏指定程序
- 版本要求:PHP>4.2.0
popen()
- 打开⼀个指向进程的管道,该进程由派⽣给定的 command 命令执⾏⽽产⽣
proc_open()
- 执⾏⼀个命令,并且打开⽤来输⼊/输出的⽂件指针
反引号(`)
- 执⾏运算符,PHP 将尝试将反引号中的内容作为 shell 命令来执⾏,并将其输出信息返回,使⽤反引号运算符的效果与函数 shell_exec() 相同
ob_start()
- 打开输出缓冲
代码执行漏洞常见的函数有哪些?
eval()
- 直接把字符串当作php代码执行。
assert()
- 判断一个表达式是否成立,返回ture or false,会执行该表达式。
- 把字符串当作php代码执行,该行为在php 8.0.0中移除
create_function()
- 创建匿名函数
- php版本8.0.0中移除
call_user_func()
- 把第⼀个参数作为回调函数调⽤
call_user_func_array()
- 调用回调参数
b)
- PHP 的函数⽀持直接由拼接的⽅式调⽤。
简述结合伪协议通过文件包含漏洞读取文件的原理?
- 当 PHP 的
include()或require()函数加载一个文件时,如果文件中包含 PHP 标签(如<?php ... ?>),PHP 解析器会强制执行其中的代码。 - 如果想获取到代码信息,使用
include()或require()无法读取到config等信息。 - 使用伪协议可以不运行php文件,实现php文件读取。
- php伪协议:
- php://
-
- 条件:
-
-
- allow_url_include=on,php://input php://stdin php://memory php://temp需要开启
- allow_url_fopen=on/off
-
-
- 作用:
-
-
- 访问请求的原始数据中的只读数据。
-
- zip://&zlib://&bzip2://
-
- 条件:
-
-
- allow_url_include=on/off
- allow_url_fopen=on/off
-
-
- 作用:
-
-
- 属于压缩流,可以访问压缩⽂件中的⼦⽂件。
-
- file://
-
- 条件:
-
-
- allow_url_include=on/off
- allow_url_fopen=on/off
-
-
- 作用:
-
-
- 用于访问本地文件系统(读取文件内容等)
- 是php默认流封装协议
- 不受allow_url_include和allow_url_fopen限制
-
-
- 语法:
file://[文件的绝对路径]
file:///etc/passwd
file://C:/Windows/win.ini
- data://
-
- 条件:
-
-
- allow_url_include=on
- allow_url_fopen=on
-
-
- 作用:
-
-
- 传递相应格式的数据。
- 可以用来执行php代码
-
- http://&https://
-
- 条件:
-
-
- allow_url_include=on
- allow_url_fopen=on
-
-
- 作用:
-
-
- 通过http1.0的GET方法,只读取访问文件资源。
-
- phar://
-
- 作用:
-
-
- 用来读取和操作这个压缩包内部文件的接口。
-