JavaScript Attacks (前端攻擊)
The attacks in this section are designed to help you learn about how JavaScript is used in the browser and how it can be manipulated. The attacks could be carried out by just analysing network traffic, but that isn't the point and it would also probably be a lot harder.
本章節中的攻擊旨在幫助您了解如何在瀏覽器中使用 JavaScript 以及如何對其進行操作,攻擊可以通過分析網絡流量來實現,但這不是本章節的重點而且可能要困難得多。
Simply submit the phrase "success" to win the level. Obviously, it isn't quite that easy, each level implements different protection mechanisms, the JavaScript included in the pages has to be analysed and then manipulated to bypass the protections.
只需提交單詞 “success” 即可攻擊成功,顯然這並不是那么容易。每個級別都實現了不同的保護機制,頁面中包含的JavaScript必須經過分析,然后才能繞過保護。
Low Level
All the JavaScript is included in the page. Read the source and work out what function is being used to generate the token required to match with the phrase and then call the function manually.
JavaScript 包含在頁面中,請手動調用與源代碼匹配的函數。
源碼審計
源碼如下,中間那一大團使用了 md5 加密生成了 token,和之前的源碼不同在於這次 token 是在前端生成的。generate_token() 函數的作用是獲取 “phrase” 參數中的值,將其的 rot13 加密的結果進行 md5 加密作為 token 的值。
<?php
$page['body'] .= <<<EOF
<script>
/*
MD5 code from here
https://github.com/blueimp/JavaScript-MD5
*/
!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function r(n,t){return n<<t|n>>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<<r%32,n[14+(r+64>>>9<<4)]=r;var e,i,a,d,h,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,d=v,h=m,g=f(g=f(g=f(g=f(g=c(g=c(g=c(g=c(g=u(g=u(g=u(g=u(g=o(g=o(g=o(g=o(g,v=o(v,m=o(m,l=o(l,g,v,m,n[e],7,-680876936),g,v,n[e+1],12,-389564586),l,g,n[e+2],17,606105819),m,l,n[e+3],22,-1044525330),v=o(v,m=o(m,l=o(l,g,v,m,n[e+4],7,-176418897),g,v,n[e+5],12,1200080426),l,g,n[e+6],17,-1473231341),m,l,n[e+7],22,-45705983),v=o(v,m=o(m,l=o(l,g,v,m,n[e+8],7,1770035416),g,v,n[e+9],12,-1958414417),l,g,n[e+10],17,-42063),m,l,n[e+11],22,-1990404162),v=o(v,m=o(m,l=o(l,g,v,m,n[e+12],7,1804603682),g,v,n[e+13],12,-40341101),l,g,n[e+14],17,-1502002290),m,l,n[e+15],22,1236535329),v=u(v,m=u(m,l=u(l,g,v,m,n[e+1],5,-165796510),g,v,n[e+6],9,-1069501632),l,g,n[e+11],14,643717713),m,l,n[e],20,-373897302),v=u(v,m=u(m,l=u(l,g,v,m,n[e+5],5,-701558691),g,v,n[e+10],9,38016083),l,g,n[e+15],14,-660478335),m,l,n[e+4],20,-405537848),v=u(v,m=u(m,l=u(l,g,v,m,n[e+9],5,568446438),g,v,n[e+14],9,-1019803690),l,g,n[e+3],14,-187363961),m,l,n[e+8],20,1163531501),v=u(v,m=u(m,l=u(l,g,v,m,n[e+13],5,-1444681467),g,v,n[e+2],9,-51403784),l,g,n[e+7],14,1735328473),m,l,n[e+12],20,-1926607734),v=c(v,m=c(m,l=c(l,g,v,m,n[e+5],4,-378558),g,v,n[e+8],11,-2022574463),l,g,n[e+11],16,1839030562),m,l,n[e+14],23,-35309556),v=c(v,m=c(m,l=c(l,g,v,m,n[e+1],4,-1530992060),g,v,n[e+4],11,1272893353),l,g,n[e+7],16,-155497632),m,l,n[e+10],23,-1094730640),v=c(v,m=c(m,l=c(l,g,v,m,n[e+13],4,681279174),g,v,n[e],11,-358537222),l,g,n[e+3],16,-722521979),m,l,n[e+6],23,76029189),v=c(v,m=c(m,l=c(l,g,v,m,n[e+9],4,-640364487),g,v,n[e+12],11,-421815835),l,g,n[e+15],16,530742520),m,l,n[e+2],23,-995338651),v=f(v,m=f(m,l=f(l,g,v,m,n[e],6,-198630844),g,v,n[e+7],10,1126891415),l,g,n[e+14],15,-1416354905),m,l,n[e+5],21,-57434055),v=f(v,m=f(m,l=f(l,g,v,m,n[e+12],6,1700485571),g,v,n[e+3],10,-1894986606),l,g,n[e+10],15,-1051523),m,l,n[e+1],21,-2054922799),v=f(v,m=f(m,l=f(l,g,v,m,n[e+8],6,1873313359),g,v,n[e+15],10,-30611744),l,g,n[e+6],15,-1560198380),m,l,n[e+13],21,1309151649),v=f(v,m=f(m,l=f(l,g,v,m,n[e+4],6,-145523070),g,v,n[e+11],10,-1120210379),l,g,n[e+2],15,718787259),m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,d),m=t(m,h);return[l,g,v,m]}function a(n){var t,r="",e=32*n.length;for(t=0;t<e;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function d(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;var e=8*n.length;for(t=0;t<e;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function h(n){return a(i(d(n),8*n.length))}function l(n,t){var r,e,o=d(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>16&&(o=i(o,8*n.length)),r=0;r<16;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(d(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),e+="0123456789abcdef".charAt(t>>>4&15)+"0123456789abcdef".charAt(15&t);return e}function v(n){return unescape(encodeURIComponent(n))}function m(n){return h(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);
function rot13(inp) {
return inp.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
}
function generate_token() {
var phrase = document.getElementById("phrase").value;
document.getElementById("token").value = md5(rot13(phrase));
}
generate_token();
</script>
EOF;
?>
攻擊方式
直接注入 “success”,網頁顯示 token 無效,說明我們不能夠直接注入。
抓包看看,請求網頁時同時提交了 token 和 phrase 參數,其中 phrase 參數是我們提交的內容。而 token 參數無論我們提交什么,都是不會變的,也就是說 token 和我們注入的參數並不會匹配。
根據源碼審計的結果,token 的生成是基於 phrase 參數的,而現在該參數已經被我們覆蓋了。因此現在我們重新拉取一下 token,在 Web 控制台運行 generate_token() 函數。
運行完之后再次提價 “success”,這次提醒我們注入成功了。
通過抓包也能看出了,現在的 token 已經被我們覆蓋掉了。
如果運行 generate_token() 函數仍然注入失敗,可以在包中手動修改 token。
Medium Level
The JavaScript has been broken out into its own file and then minimized. You need to view the source for the included file and then work out what it is doing. Both Firefox and Chrome have a Pretty Print feature which attempts to reverse the compression and display code in a readable way.
JavaScript 被保存在文件中,您需要查看包含文件的源代碼,然后審計出它執行了什么操作。Firefox 和 Chrome 都有一個效果不錯的顯示功能,它試圖以可讀的方式反轉壓縮和顯示代碼。
源碼審計
生成 token 的函數被放在單獨的js文件中,生成的方式是將 "XX" + phrase 變量的值 + "XX"字符串反轉作為 token。
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")
}
攻擊方式
攻擊的方法和 low 差不多,首先注入 “success” 之后抓包看看,現在的 token 是 “XXChangMeXX” 的反轉。
控制台運行下 do_elsesomething("XX") 函數,再次注入 “success” 即可,如果沒反應就手動改下包就行。
High Level
The JavaScript has been obfuscated by at least one engine. You are going to need to step through the code to work out what is useful, what is garbage and what is needed to complete the mission.
至少有一個 JavaScript 混淆了,你需要逐步檢查代碼,找出什么是有用的,什么是無用的,什么是完成任務所需的。
源碼審計
源碼是一團亂碼,這是典型的 JS 混淆,使用還原工具得到源碼后得到關鍵代碼部分如下。
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);
由於執行 token_part_2("XX") 有 300 毫秒延時,所以 token_part_1("ABCD", 44) 會被先執行,而 token_part_3() 則是和提交按鈕的 click 事件一起執行。
攻擊方式
和前 2 個等級差不多,依次執行 token_part_1("ABCD", 44) 和 token_part_2("XX"),最后點擊提交執行 token_part_3()。
impossible Level
You can never trust the user and have to assume that any code sent to the user can be manipulated or bypassed and so there is no impossible level.
你永遠不能信任用戶,必須假設發送給用戶的任何代碼都可以被操縱或繞過,因此沒有不可能的級別。