High Level
查看源码
high.php
<?php $headerCSP = "Content-Security-Policy: script-src 'self';"; header($headerCSP); ?>
<?php if (isset ($_POST['include'])) { $page[ 'body' ] .= " " . $_POST['include'] . " "; } $page[ 'body' ] .= ' <form name="csp" method="POST"> <p>The page makes a call to ' . DVWA_WEB_PAGE_TO_ROOT . '/vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code.</p> <p>1+2+3+4+5=<span id="answer"></span></p> <input type="button" id="solve" value="Solve the sum" /> </form> <script src="source/high.js"></script> ';
high.js
function clickButton() { var s = document.createElement("script"); s.src = "source/jsonp.php?callback=solveSum"; document.body.appendChild(s); } function solveSum(obj) { if ("answer" in obj) { document.getElementById("answer").innerHTML = obj['answer']; } } var solve_button = document.getElementById ("solve"); if (solve_button) { solve_button.addEventListener("click", function() { clickButton(); }); }
这个级别已经没有输入框了,不过题目已经给了足够多的提示。
首先先看一下 CSP 头,发现只有
script-src 'self';,
看来只允许本界面加载的 javascript 执行。然后研究了一下这个点击显示答案的逻辑(逻辑在
source/high.js
里), 大致如下: 点击按钮 -> js 生成一个 script 标签(src 指向 source/jsonp.php?callback=solveNum), 并把它加入到 DOM 中 -> js 中定义了一个 solveNum 的函数 -> 因此 script 标签会把远程加载的 solveSum({"answer":"15"}) 当作 js 代码执行, 而这个形式正好就是调用了 solveSum 函数, 然后这个函数就会在界面适当的位置写入答案。一般是没办法修改服务器上的 jsonp.php 文件的,但是在查看服务端源码的时,可以看到下面代码:
if (isset ($_POST['include'])) { $page[ 'body' ] .= " " . $_POST['include'] . " "; }
竟然还偷偷接收 include 参数(不清楚是不是作者复用了之前 Medium 的代码). 总之, 这肯定能作为一个注入点, 我开始打算用简单粗暴的 <script>alert('hacked')</script>
来搞定的, 谁知道, 这种是属于 'unsafe-inline' 形式的, 所以被限制执行了. 嗯... 既然如此的话, 那我就利用 src 吧.
jsonp.php
<?php
header("Content-Type: application/json; charset=UTF-8");
if (array_key_exists ("callback", $_GET)) {
$callback = $_GET['callback'];
} else {
return "";
}
$outp = array ("answer" => "15");
echo $callback . "(".json_encode($outp).")";
?>
这个即使你不看源码, 你做几个测试也会发现, 那个 callback 参数可以被操控以生成任何你想要得到的结果, 比如 alert, 因此可以构造 Payload: <script src="source/jsonp.php?callback=alert('hacked');"></script>
, 并把这个当做 include 参数传给界面就 注入成功!
PS:坦白说,这个我还不太理解,也没试出来。
参考:
https://www.cnblogs.com/-zhong/p/10906270.html
https://zhuanlan.zhihu.com/p/110012962