最近零零散散在各种从各种渠道参加的赛事上写了些水题,一直在纠结到底要不要记。不过既然都做了,感觉过程中也有不少骚操作,就稍微记一记。正好也记上这些比赛里没写出来的题目的复现。
Dawg CTF 2020

Free WIFI Part 1
附件给了个 free-wifi.pcapng,导入到 WireShark 里略微分析,可以发现一个请求。
1 | [Full request URI: http://freewifi.ctf.umbccd.io/staff.html] |
尝试访问 staff.html,并根据上述请求构造一个 POST 请求,就能在页面底端拿到 flag。
1 | DawgCTF{w31c0m3_tO_d@wgs3c_!nt3rn@t!0n@1} |
The Lady is a Smuggler
这题一开始给了个页面,下面有一段加密,但其实解密那段得出来的 flag 是无效的。真实的 flag 在页面的源码中。
1 | DawgCTF{ClearEdge_ElizebethSmith} |
Tracking
这题页面感觉跟前面那个一样,首先看一手源码。找到一段 JavaScript。
1 | alert(String.fromCharCode(68,97,119,103,67,84,70,123,67,108,101,97,114, 69,100,103,101,95,117,110,105,125)) |
放到 Console 里面运行就得到了 flag。
1 | DawgCTF{ClearEdge_uni} |
Deep CTF

Oh JS!
JSFuck
这题开门见山地给了个登录的 form,但其实查看页面源代码可以看到一段 JSFuck,把它掐头去尾放到 Console 跑一下可以发现线索。
1 | ƒ anonymous( |
于是直接跳过登录的步骤,访问 .../4d4932602a75414640946d38ea6fefbf.php
得到 flag。
1 | d33p{g0tta_kn0w_y0ur_J4v4Scr1pt} |
Magic Word!
Regexp
这题给出了页面的源代码和 Try to reach get_mad_and_give_flag()
的提示。
1 | <?php |
既然是 preg_replace()
,之前在 SQL 注入的题目里面遇到过,只需要夹着写一遍就行了。于是构造 ?magic_word=d3d33p3p
得到 flag。
1 | d33p{d33p_p33d} |
Nothing is Impossible
这题给的是一个可以执行 php 代码的框,于是果断试了一手 system()
,发现仍然可以使用。根据题目提示,flag 在 /tmp/flag.php
。于是直接使用 od
构造了 system("od -A d -c /tmp/flag.php")
,得到结果。
1 | 0000000 < ? p h p \n e c h o " d 3 3 p 0000016 { f 4 s t _ C G 1 _ S S R F _ p 0000032 0 w 3 r ! ! } " ; \n 0000042 |
整理之后得到 flag。
1 | d33p{f4st_CG1_SSRF_p0w3r!!} |
Did You Got Trolled?
这题我成功地被绕了进去,他给了好多动物的叫声,我还以为是动物园。还有那个假装可以注入的地方,也是很好笑。其实真正的要点在找到两个 key。在学长的提示下,我在 .../css/clean-blog.css
下找到了 Key1。其实他是有给提示的,只有那一个页面引入了同样的两份 CSS,且重复的那份是没有压缩的。
1 | /* |
接下来的那一份就得扫目录了,是在 .../robots.txt
里面有个提示,写着 Disallow /deep.php
。访问这个页面可以得到一个提示。
1 | MAINTENANCE |
很容易知道这是一个文件包含,然后再看一手页面源码,可以找到 <!--Creds in /home/ubuntu/key2.txt -->
的注释。于是构造 ?page=/home/ubuntu/key2.txt
得到 Key2。
1 | key2 = flag0x085927 |
回到 .../post.html
提交两个 Key,可以得到 flag。
1 | D33P{h3r3_1s_y0ur_7r0ll_fl4g} |
Greetings!
SSTI
根据题目提示,传递一个 GET 参数 ?name=you
可以得到 Hello you 的反馈。于是试了一手 {{7 * 7}}
得到了 Hello 49 的反馈,可以确定是 SSTI 的考点,然后发现了 tornado。顺势试了下 ?name={{__import__("os").popen("ls").read()}}
找到了 flag.txt
。于是再构造 cat flag.txt
得到 flag。
1 | d33p{I_<3_3000} |
Hack MEEEE
Ruby
上来先看了一手这题源码,找到了 <!-- This application is made using ruby! <3 -->
的提示,然后当时触及到了知识盲区,就没管。其实翻了一波手册再查了一下之后发现很简单。页面请求传递了两个 POST 参数。这里有个坑,method
要放在前面,不然 POST 本身的换行符加上之后可能不会有正确结果返回。(报错在页面源码的注释中可以看到)
按照 Ruby 的手册,使用 method=methods
和 method=private_methods
可以查看当前类下包含的方法。于是找到了可以利用的反引号。手册参考 结合上 instance_eval
这个方法就能达成目的。
因此,构造 method=instance_eval&message=`ls`
的 POST 请求参数,可以得到 flag.txt 位于当前目录下的线索,于是只需要再构造 cat flag.txt
即可得到 flag。
1 | d33p{send_is_a_very_dangerous_method} |
TG:Hack

Shop
题目一开始,给了 bank 和 store 的两个页面,我们知道“衬衫的价格是九镑十五便士”。啊,不是,是二十五美元。这题嘛,其实不能按照一般思路去想,一开始我在 bank 页面试了好久都加不上钱,然后就只能去 store 页面找。每买一件东西都会传递两个 POST 参数,分别指代物品类别和钱数。所以,把钱数想办法变成负数就可以从商店“索要”金钱了。但是还有一个点,使用已经存在的物品 ID 不可信,所以就随便整个其他的 ID 就行。这里还有一个坑,POST 参数最后的换行符会有影响(所以 HackBar 不行),我使用某在线的 POST 工具就成功达成目的了。最后就可以买到 flag。
1 | TG20{I_just_want_to_buy_a_real_flag} |
Redux
这题,说实话我其实没太看懂。首先随便填一填他给的表,然后提交,Console 里就能看到一条消息 The form has been submitted! Look at the Redux store!
。我一开始也想知道这个 Redux store 指的是哪里,但是找了几下没找到。看到这条消息是来自 form.js 的,于是就顺手点开看了看。
1 |
|
于是就找到了 flag。
1 | TG20{always_disable_redux_dev_tools} |
AUCTF

Miyazaki Trivia
打开页面有 Find this special file.
的提示,于是找到 .../robots.txt
。打开之后又是新的提示 VIDEO GAME TRIVIA: What is the adage of Byrgenwerth scholars? MAKE a GET request to this page with a header named 'answer' to submit your answer.
,查了一下之后得到答案,于是构造 ?answer=Fear the Old Blood
得到 flag。
1 | auctf{f3ar_z_olD3_8l0oD} |
Quick Maths
这题先随便算几个数,发现可以正常算出结果。(不太记得了,写的时候好像算了 7 * 7 啥的,得到的都是49)于是顺手构造了个 statement=system("ls")
然后发现有返回结果。于是就安排上 statement=system("cat ./index.php")
就拿到了 flag。需要注意的是,这里的请求包需要用 Burp Suite 发送才能得到返回的结果。
1 | auctf{p6p_1nj3c7i0n_iz_k:3w1} |
gg no re
这题一开始给了个 authentication.js,略微分析之后可以发现是 Base64,取出关键信息 TWFrZSBhIEdFVCByZXF1ZXN0IHRvIC9oaWRkZW4vbmV4dHN0ZXAucGhw
再解码,得到 Make a GET request to /hidden/nextstep.php
。按照提示进行,在 Header 中可以找到下一步线索,ROT13: Znxr n CBFG erdhrfg gb /ncv/svany. CuC
。使用工具解密一下,得到 Make a POST request to /api/ final. PhP
,接着按照提示 Send a request with the flag variable set
进行,构造 ?flag=1
即可得到 flag。
1 | auctf{1_w@s_laZ_w1t_dis_0N3} |
API madness
按照提示访问 .../static/help
可以看到有三个 API。先尝试一下 login,这里有个坑,要用 curl 发请求才能成功 curl -X POST -H "Content-Type: application/json" -d '{"username":"lemon","password":"password"}' host/api/login
,而且响应的时间很长很长,返回的数据是一个报错的页面,里面包含了一个不一样的接口 .../api/login_check
。curl 访问之后得到了一个为 null 的 token。看起来像是假的一样,但是就像爱情,你不去尝试怎么知道结果呢?于是按照 API 接口接着往前冲,构造 curl -X POST -H "Content-Type: application/json" -d '{"dir":"/","token":"null"}' host/api/ftp/dir
,返回结果中看到了 flag.txt。于是构造 curl -X POST -H "Content-Type: application/json" -d '{"file":"/flag.txt","token":"null"}' host/api/ftp/get_file
得到结果。
1 | { |
取出 YXVjdGZ7MHdAc3BfNnJvSzNOX0B1dGh9Cg==
之后 Base64 解码即得 flag。
1 | auctf{0w@sp_6roK3N_@uth} |
GWCTF 2019

我有一个数据库
这题上来就说了数据库,但是打开页面发现没得入口,只有两行字。于是尝试找了一下特殊文件,找到了 robots.txt。文件里给了个 phpinfo.php,但是打开之后没找到啥利用点。但是由于自己搭环境的时候出了些问题,于是去查了一波,就事先知道了这题有个 phpmyadmin,如果真的打比赛估计找不到这个点。不过他给的 phpmyadmin 很奇怪,不需要登录就能操作数据库。于是就去查了一波相关的知识点,找到了 CVE-2018-12613。
于是照着教程,构造 .../index.php?target=db_events.php%3f/../../../../../flag
就能够包含到在根目录的 flag。
1 | gwctf{JUst_q_1I111l1Il11DAYS} |
枯燥的抽奖
页面给了十个随机字母,查看网页源代码可以发现一个 check.php,访问之后可以拿到随机数生成的方法,按照 MRCTF-Ezaudit 的套路用 php_mt_seed 这个工具算一波随机数种子,然后再用 PHP 生成后面十位就行了。这里踩了一个坑,工具的版本很重要,我之前使用的那个在这题算不出来而且能算出来的也不会告知 PHP 的版本号。至于生成适合工具使用的参数格式嘛,我写了一段 PHP 代码。
1 | $str = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
如果前面的步骤都没有错,算出来的随机数种子应该是 951373997
。放到给出的源码中然后解除 10 位的限制,可以得到二十位的字符串 oS668h2wc93iAcrwCuZQ
。提交到页面上即可得到 flag。
1 | flag{Y0u_wIN_abcdefghijklmnopqrstuvwxyz} |
(后面的题目环境搭好了 题目好像很顶 让我慢慢写一波)
Sharky CTF 2020

XXExternalXX
上来点 Show stored data 探索一波,注意到了地址栏的 ?xml=data.xml
察觉到可能是 XXE。随便填充之后在报错里发现了 Trying to get property 'data' of non-object
,于是根据题目描述顺手构造一波。
1 | <?xml version="1.0" encoding="UTF-8"?> |
这里因为是个 GET 参数,所以得想办法给构造的 payload 一个直链才能成功,达成之后可得 flag。
1 | shkCTF{G3T_XX3D_f5ba4f9f9c9e0f41dd9df266b391447a} |
Logs In ! Part 1
这题千万不要被标题迷惑,访问页面之后可以在左下角找到 Controller 的页面,顺手访问一波之后可以看到两个路由,访问其中一个 /e48e13207341b6bffb7fb1622282247b/debug
可得 flag。
1 | shkCTF{0h_N0_Y0U_H4V3_4N_0P3N_SYNF0NY_D3V_M0D3_1787a60ce7970e2273f7df8d11618475} |
Containment Forever
这题的两条 flag 没办法打开,但是有其他记录可以访问。根据地址猜测应该是要自己找到这个类似于 ID 的东西。于是尝试随便改一波,发现报错了且找到了 mongoose
的字样。在大佬的指引下找到了 参考,于是开始把页面上原来的 ID 拆开。
1 | string [] items = { |
然后发现随机数是固定的,也就是说只需要时间戳和 ID。时间戳只需要从两条记录上找然后转换一下,很容易得到。
1 | 2020-03-21 09:13:22 1584782002 |
至于 ID 的话只需要根据已经有的 ID 在附近枚举一下就可以了。于是写段代码生成一下。
1 | Int64[] timeStamps = {1584782002, 1586793018}; |
将得到的几个结果逐一尝试可以得到包含 flag 的两个记录的地址。
1 | .../item/5e75dab2d7b1600013655bb8 |
将得到的 flag 拼接在一起,得到 flag。
1 | shkCTF{IDOR_IS_ALS0_P0SSIBLE_W1TH_CUST0M_ID!_f878b1c38e20617a8fbd20d97524a515} |
Aqua World
打开页面,发现导航有个点不动的地方,审查元素访问到 .../admin-query?flag=flag
。页面提示需要修改 netloc 为本地。在各种修改 header 之后看到了题目给的 hint:WTF this PYTHON version is deprecated!!!
。于是顺着线索找到了 CVE-2019-9636 并根据其中给出的例子构造(Authorization 的 header 是题目本身要求的)。
1 | import requests |
需要注意的是,这里执行脚本的 Python 也需要使用有漏洞的版本,否则请求无法成功完成。(这部分还需要复现
使用特定版本发起请求后即可在响应中找到 flag。
1 | shkCTF{NFKC_normalization_can_be_dangerous!_8471b9b2da83011a07efc2899819da65} |