文章目录
SQL注入WAF绕过
1、变换大小写
- WAF拦截了union,那就使用Union、UnloN等方式绕过
2、16进制编码
- WAF检测敏感字’admin’,则可以用0x61646d696e代替
- WAF检测敏感字select,可以在URL中将select变成%73elEcT结合大小写变换绕过WAF
- 用%09、%0a、%0b、%Oc、%0d、%a0、/**/、/somewords/等来替换空格
3、利用注释符
- 适用于WAF只过滤一次敏感字的情况,比如WAF只过滤一次union和select,则可以用/**/绕过:?id=1/union/union /select/select 1,2,3
4、重写
- 适用于WAF只过滤一次敏感字的情况,比如WAF只过滤一次union,则可以写出类似ununionion这样的:?id=1 ununionion select 1,2,3
5、比较操作符替换
- WAF过滤等号(=),可以用>和<来判断,比如要判断某个值是不是5,则可以判断是不是大于4,且小于6
- WAF将=、>、<全部过滤,则可以利用like来绕过,如:?id=1’ or … like 1
- WAF将=、>、<全部过滤,也可以用strcmp()函数绕过
6、同功能函数替换
- 适用于某一函数被过滤的情况,如substring()被WAF过滤,可以用同功能的mid(),substr()等函数来替换,都是用来取字符串的某一位字符
7、二阶注入
简介: 指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入
补充: mysql_escape_string()函数,该函数和mysql_real_escape_string一样可以转移特殊字符,但不同的是经过mysql_escape_string处理的参数在存入数据库时会被还原成原来的数据
场景: 设想在登录页面username和password都经过了mysql_real_escape_string函数的转义,无法造成SQL注入。但注册页面使用的是mysql_escape_string函数,那么我们注册一个名为admin’#的用户,密码设为123456,登录该用户后,在修改密码页面修改密码为666666,这时admin’#的密码没有被修改,反而是admin的密码被修改了。
原理: 后端数据库执行的命令为,UPDATE users SET PASSWORD=‘666666’ where username=‘admin’#’ and password=‘123456’,等价于,UPDATE users SET PASSWORD=‘666666’ where username=‘admin’
8、宽字节注入(%df’)
前言:
- 当某字符的大小为一个字节时,称其字符为窄字节
- 当某字符的大小为两个字节时,称其字符为宽字节
- 所有英文默认占一个字节,汉字占两个字节
- 常见的宽字节编码:GB2312,GBK,GB18030,BIG5,Shift_JIS
原理: MySQL数据库编码与PHP编码不同导致,如MySQL数据库使用GBK编码而PHP编码为UTF8。MySQL认为两个字符是一个汉字(前一个字符ascii码要大于128,如%df),而当我们输入%df和单引号(%df’)时,MySQL会调用转义函数如addslashes,将单引号转义(添加 \ )后整个为 %df’ ,其中 \ 的十六进制是%5c,即 %df%5c’ ,而MySQL的GBK编码会认为%df%5c是一个汉字(運),而此时单引号仍然存在,可以实现闭合,从而造成SQL注入。
参考链接: 渗透测试-SQL注入之宽字节注入
SQL注入防护方法
1、限制数据类型
- 比如使用函数 is_numeric() 判断为数字时才执行下一步,这样限制了字符从而也就限制了注入,但针对此函数可以16进制编码绕过
2、正则表达式匹配
比如这段PHP代码
$id=$_POST['id'];
if (preg_match('/and|select|insert|insert|update|[A-Za-z]|/d+:/i', $id)) {
die('stop hacking!');
} else {
echo 'good';
}
3、转义函数
- php自带的magic_quotes_gpc函数,不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致双层转义
- addslashes、mysql_escape_string、mysql_real_escapse_string
4、SQL语句预编译
- 防御SQL注入的最佳方式就是使用预编译SQL语句,绑定变量
- 预编译相当于是将数据于代码分离的方式,把传入的参数绑定为一个变量,用?表示,攻击者无法改变SQL的结构
比如这段PHP代码
String query="select password from users where username='?' ";
$query="INSERT INTO myCity (Name,CountryCode,District) VALUES (?,?,?)";
$stmt=$mysqli->prepare($query);
$stmt->bind_param("sss",$val1,$val2,$val3);
$val1="Stuttgart";
$val2="DEU";
$val3="Baden";
//execute the statement
$stmt->execute();
即使攻击者插入类似 admin’ or 1=1# 的字符串,预编译会将传入的 admin’ or 1=1# 当做纯字符串的形式作为username执行,避免了类似sql语句拼接、闭合等非法操作