1. 概要
外国人が言及したJavaScriptの機能ハイジャック
ハイジャック技術。私が最初に目にしたのは、Kenshin と問題について話し合っていたときのコードで、大まかに次のように書かれていました。
この使い方は非常に賢くて斬新だと思うので、API Hook に似ているので、単純に JavaScript 関数と呼びます。
フック、つまり関数ハイジャックです。この関数呼び出しをハイジャックする目的は、js 関数の実装を置き換えることによって達成されます。完全なフック アラート関数の例は次のとおりです。
<script type="text/javascript"> <!-- var _alert = alert; window.alert = function(s) { if (confirm("是否要弹框框,内容是\"" + s + "\"?")) { _alert(s); } } //--> </script> <html> <body> <input type="button" onclick="javascript: alert('Hello World!')" value="test" /> </body> </html>
2. アプリケーションの例
1. 簡単な JavaScript を実装します。
デバッガ、ここではデバッガがより注目を集めていると言われていますが、実際にはデバッガの機能に少し似ており、主に関数のブレークを実現するために js 関数のハイジャックを使用します。
ポイントとして、簡単な例を見てみましょう:
<script type="text/javascript"> <!-- var _eval = eval; eval = function(s) { if (confirm("eval被调用\n\n调用函数\n" + eval.caller + "\n\n调用参数\n" + s)) { _eval(s); } } //--> </script> <html> <head> </head> <body> <script type="text/javascript"> <!-- function test() { var a = "alert(1)"; eval(a); } function t() { test(); } t(); //--> </script> </body> </html>
js 関数ハイジャックによって関数の実行を中断し、パラメーターと関数呼び出し元のコードを表示します。完全な例の効果を見てみましょう。 :
デバッグ コマンド:
bp <関数名> - 関数にブレークポイントを設定します。例: "bp
window.alert"。
bl - すべてのブレークポイントをリストします。
bc <ブレークポイント番号> -
指定した番号でブレークポイントを削除します (例: "bc 0")。
>bp window.alert
* 関数「window.alert」のブレークポイント
>bl
* 1 ブレークポイント:
0 - window.alert
>bc 0
* 関数「window.alert」のブレークポイントは正常に削除されました。
ここでは、ブレークポイントの設定、ブレークポイントの表示、およびブレークポイントの削除のデモを示します。完全なコードは、この記事の付録 [1] に記載されています。
2.
クロスサイト テスターをリアルタイムで捕捉するためのトラップを設定します。クロスサイトを行う人は常にアラートを使用して、誰かが Web サイトの XSS をテストしているかどうかを監視する必要があります。監視したいページ。
アラート関数、アラートの呼び出し状況を記録します:
<script type="text/javascript"> <!-- function log(s) { var img = new Image(); img.style.width = img.style.height = 0; img.src = "http://yousite.com/log.php?caller=" + encodeURIComponent(s); } var _alert = alert; window.alert = function(s) { log(alert.caller); _alert(s); } //--> </script>
document.write(document.location.hash);
このようなクロスサイトは http に反映できません。
そのため、従来のスキャン方法ではスキャンできません。しかし、前の例に触発された人なら、DOM をセットアップする方法を必ず思いつくでしょう。
XSS により最終的にアラートが実行されるため、アラート関数をフックしてトラップをセットアップします。XSS が成功すると、アラート関数が呼び出され、トラップがトリガーされて結果が記録され、DOM を実装できるようになります。
XSS の自動スキャンの場合、トラップ コードは上記と同様です。
4.
js ハイジャックを柔軟に使用して、ページのコード分析作業を支援します。たとえば、Web ページのトロイの木馬を分析する場合、暗号化は eval または document.write を通じて実行されることが多いため、フックを作成します。
復号化を支援する eval および document.write 用の小さなツール:
<script type="text/javascript"> <!-- var _eval = eval; eval = window.execScript = window.document.write = window.document.writeln = function(s) { document.getElementById("output").value = s; } //--> </script> <html> <body> input: <textarea id="input" cols="80" rows="10"></textarea> <input type="button" onclick="javascript: _eval(document.getElementById('input').value);" value="decode" /> <br /> output: <textarea id="output" cols="80" rows="10"></textarea> </body> </html>
デコードされたコードを出力ボックスに出力します:
alert(1);
もちろん、より柔軟なアプリケーションを考えることもできます:)
3.
ハイジャックについて話すときは、ハイジャック対策についても話さなければなりません。堅牢な xss プレイロードを作成したい場合は、解決すべき 2 つの問題があります。
ハイジャック対策が行われているかどうかを判断する方法。乗っ取られた?
乗っ取られたことに気付いた場合、どのように対処すればよいでしょうか?
1. 関数がハイジャックされているかどうかを判断するのは簡単です。関数がフックされる前と後の違いを比較するのは簡単です。
<textarea id="tb1" cols="80" rows="8"></textarea> <script type="text/javascript"> <!-- document.getElementById("tb1").value = eval + "\n"; var _eval = eval; eval = function(s) { alert(s); _eval(s); } document.getElementById("tb1").value += eval; //--> </script>
结果:
function eval() {
[native code]
}
function(s) {
alert(s);
_eval(s);
}
我们发现那些内置函数是[native
code],而自定义的则是具体的函数定义,用这个特征就可以简单的检测函数是否被劫持:
function checkHook(proc) {
if
(proc.toString().indexOf("[native code]") > 0) {
return false;
} else
{
return true;
}
}
2.
如何反劫持,第一个想法就是恢复被劫持的函数,如果劫持的人把原函数保存在某个变量里那还好办,直接调用原函数就可以了,但是劫持者自己也没保存副本怎么办,只能自己创建个新的环境,然后用新环境里的干净的函数来恢复我们这里被hook了的,怎么创建新环境?整个新的iframe好了,里面就是个全新的环境。ok,动手吧:
function unHook(proc) { var f = document.createElement("iframe"); f.style.border = "0"; f.style.width = "0"; f.style.height = "0"; document.body.appendChild(f); var d = f.contentWindow.document; d.write("<script type=\"text/javascript\">window.parent.escape = escape;<\/script>"); d.close(); }
综合1、2节,整个测试代码如下:
<script type="text/javascript"> <!-- escape = function(s) { return s; } //--> </script> <html> <body> <input type="button" onclick="javascript: test();" value="test" /> <script type="text/javascript"> <!-- function test() { alert(escape("s y")); if (checkHook(escape)) { unHook(escape); } alert(escape("s y")); } function checkHook(proc) { if (proc.toString().indexOf("[native code]") > 0) { return false; } else { return true; } } function unHook(proc) { var f = document.createElement("iframe"); f.style.border = "0"; f.style.width = "0"; f.style.height = "0"; document.body.appendChild(f); var d = f.contentWindow.document; d.write("<script type=\"text/javascript\">window.parent.escape = escape;<\/script>"); d.close(); } //--> </script> </body> </html>
3. 不是上面两个问题都解决了么,为什么要有第3节?因为那不是个最好的解决办法,既然我们可以创建全新的iframe,何不把代码直接放到全新iframe里执行呢,这样做的话绿色环保,既不用考虑当前context里的hook问题,也不用改动当前context,不会影响本身的程序执行。给出两个比较通用点的函数:
function createIframe(w) { var d = w.document; var newIframe = d.createElement("iframe"); newIframe.style.width = 0; newIframe.style.height = 0; d.body.appendChild(newIframe); newIframe.contentWindow.document.write("<html><body></body></html>"); return newIframe; } function injectScriptIntoIframe(f, proc) { var d = f.contentWindow.document; var s = "<script>\n(" + proc.toString() + ")();\n</script>"; d.write(s); } 把你的payload封装进一个函数,然后调用这两个方法来在iframe里执行: function payload() { // your code goes here } var f = createIframe(top); injectScriptIntoIframe(f, payload);
四、最后
由于国内很少有见文章提及这个东西,所以才草成这篇,希望能够抛砖引玉。由于本人水平有限,难免有错误或者疏漏之处请谅解,没有说清楚的地方,欢迎和我交流。
还有就是一些不得不感谢的人,感谢剑心一直以来毫无保留的交流,感谢黑锅多次鼓励我把自己的心得体会写成文字,感谢幻影所有的朋友们、B.C.T的朋友们以及群里那帮经常一起扯淡的朋友们。
广告一下,没法幻影blog的朋友,可以添加hosts来突破:
72.14.219.190 pstgroup.blogspot.com