DDCTF 2019
最近打了 DDCTF。
真-签到题
在公告里面找到 flag
Windows Reverse1
加了 UPX 的壳,在 linux 下用 upx -d 脱掉,然后分析代码
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
获取用户输入之后就进入 check 函数
1 | unsigned int __cdecl check(const char *a1) |
静态来看似乎是以输入为索引,在一个表中查找相应的字符出来,后续用 OD 调试也印证了这一猜测。
随后将取出的字符和 “DDCTF{reverseME}” 去比较,如果相等说明输入是正确的,那么编写脚本找出这些 index 即可。
1 | s = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32] |
重新排列字符即可得到 flag (当然也可以通过调试直接拿 flag)。
flag: ZZ[JX#,9(9,+9QY!
Windows Reverse2
加了 ASP 的壳,我试了几个脱壳工具都不能正常脱壳,索性带着壳直接调试,利用 ESP 定律 + 字符串搜索定位到主函数,简单看了一下,第一个关键函数在 0x11611f0(这个地址可能不一样,但是就在 scanf 函数下方),它用来验证输入是否由 16 进制字符串构成,即我们的输入只能由 09 + AF 组成,随后还会将输入两两一组转换成真正的十六进制。
另外一个函数动态分析看到解密了字符串,’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/‘,很明显是 BASE64 算法的表盘,猜测这个函数实现了 BASE64 编码或者解码,最终将结果和 reverse+ 进行比较。编写脚本对 reverse+ 字符串进行 base64 解码得到正确的 flag。
1 | import base64 |
flag: ADEBDEAEC7BE
[PWN] strike
漏洞在于输入长度的时候没有考虑为负数的情况,当输入一个负数的时候发生整数溢出回绕到一个非常大的正数,导致栈溢出。
另外在读取 username 的时候没有补零,导致信息泄露。
思路是通过信息泄露找到 libc 的地址和 ebp 的地址(栈的地址),然后通过栈溢出返回到 onegadget getshell。
注意到发生栈溢出的函数结尾有以下汇编代码
1 | lea esp, [ebp-8] |
并不是常规的 leave ret 结构,所以构造利用链就稍稍复杂一些,另外服务器上面的 libc 和本地的 libc 好像稍有不同。
1 | # coding=utf-8 |
flag: DDCTF{s0_3asy_St4ck0verfl0w_r1ght?}
Confused
用 objective-C 编写的程序, IDA 打开程序发现反编译的效果相当不错,并且没有去除符号信息。
不能执行程序就只能静态分析,在 checkcode 函数中找到了具体的验证算法,简单分析一下,程序实现了一个虚拟机,从代码段取出 opcode,然后利用 loader 函数执行。
1 | bool __fastcall loader(vm *a1) |
其中虚拟机结构体恢复如下
1 | 00000000 vm struc ; (sizeof=0xB0, mappedto_59) |
opcode 从 0x000000100001984 地址开始,分析前几条指令得到大致如下的程序逻辑
1 | vm -> temp1 = 0x66 |
先取出一个字节,然后做一个偏移量为 2 的凯撒加密,再和我们的输入进行比较。
将里面的密文取出来,做一次凯撒解密即可得到 flag
flag: DDCTF{helloYouGotTheFlag}
Wireshark
题目给了一个数据包,直接用 wireshark 打开,过滤出 http 流量,首先找到了一个网站
1 | http://tools.jb51.net/aideddesign/img_add_info |
猜测流量包里面用到了这个隐写工具。
然后在一个上传图片的流量包中找到一个 绿色钥匙的图片,在 linux 下面提示 CRC 错误,这通常是由于图片长宽错误导致的。利用 010 editor 修改图片高度拿到一个 key: 57pmYyWt
又找到了另外两张图片,内容一样但是大小不同,将这两张图片传到之前的网站上进行解密,从较大的那张图(1.9M 左右)取得 flag
flag: DDCTF{QEWokcpHeUo2WOfBIN7pogIWsF04iRjt}
滴~
观察 url
1 | http://117.51.150.246/index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09 |
将 jpg 参数后面跟的字符串解码得出字符串 flag.jpg,也就是说我们传入的参数也要进行 转 16 进制 -> BASE64ENCODE -> BASE64ENCODE 才行。
先读取一下 index.php 的内容
1 |
|
意思大概是输入的字符串只能包含字母数字和小数点,并且如果包含 config 字符串,会被替换成 !。
访问给出的博客,按照下面的日期找到博主的一篇文章
1 | https://blog.csdn.net/FengBanLiuYun/article/details/80913909 |
尝试访问 practice.txt.swp 得到提示
1 | f1ag!ddctf.php |
于是构造 jpg 参数为
1 | TmpZek1UWXhOamMyTXpabU5tVTJOalk1TmpjMk5EWTBOak0zTkRZMk1tVTNNRFk0TnpBPQ== |
得到代码
1 |
|
再构造 url
1 | http://117.51.150.246/f1ag!ddctf.php?uid=f1ag!ddctf.php&k=practice.txt.swp |
得到 flag: DDCTF{436f6e67726174756c6174696f6e73}
obfuscating macros
控制流平坦化的一道题目,混淆了两个函数。
首先尝试使用科恩实验室给的脚本 deflat.py,但是在符号执行阶段会卡住,不知道是不是 angr 版本的问题,修复操作失败,但是从 IDA 中看被混淆的函数的伪代码感觉真正的逻辑不会太复杂,于是采用调试的方法,通过在 flag 的位置下硬件断点来追踪程序流程。
总结出两个被混淆的函数的流程,第一个函数限制输入必须是十六进制的字符,和 Windows Reverse2 的算法类似,之后会将输入转换成真正的 16 进制数据。
第二个函数是主要算法,流程如下
1 | 检查 flag[0] 是否等于 0? |
将硬编码的字节全部取出就可以得到 flag
flag: 79406C61E5EEF319CECEE2ED8498
Web 签到题
进去提示需要先获取权限,在 JS 中发现如下代码
1 | function auth() { |
那么就在 POST 请求头添加一个 didictf_username 字段试试
1 | 您当前当前权限为管理员----请访问:app\/fL2XID2i0Cdh.php |
拿到源代码
1 | url:app/Application.php |
1 | url:app/Session.php |
存在格式化字符串漏洞
1 | if(!empty($_POST["nickname"])) { |
将 nickname 设置为 %s 可以泄露出 key
1 | #coding: utf-8 |
1 | {"errMsg":"success","data":"\u60a8\u5f53\u524d\u5f53\u524d\u6743\u9650\u4e3a\u7ba1\u7406\u5458----\u8bf7\u8bbf\u95ee:app\/fL2XID2i0Cdh.php"}{"errMsg":"Welcome","data":"Welcome my friend EzblrbNS"}{"errMsg":"sucess","data":"DiDI Welcome you Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko\/20100101 Firefox\/66.0"} |
得到 key:EzblrbNS
然后利用 Application 中析构函数读文件的能力读取 flag ,构造一个满足要求的 cookie。
1 | #coding: utf-8 |
1 | {"errMsg":"success","data":"\u60a8\u5f53\u524d\u5f53\u524d\u6743\u9650\u4e3a\u7ba1\u7406\u5458----\u8bf7\u8bbf\u95ee:app\/fL2XID2i0Cdh.php"}{"errMsg":"Congratulations","data":"DDCTF{ddctf2019_G4uqwj6E_pHVlHIDDGdV8qA2j}"} |
flag: DDCTF{ddctf2019_G4uqwj6E_pHVlHIDDGdV8qA2j}
联盟决策大会
题目给出了很明确的提示,Shamir秘密分享方案,从 wiki 上面简单了解了一下原理,大概意思就是将一个秘密按照一定的算法分成 k 份(分给 k 个人),并且制定了一个方案,大于等于 n 个人(n < k) 可以将自己手中的秘密合并起来得到完整的秘密,但是小于 n 个人是无论如何都不能解出原始的秘密的。
plaid CTF 2012 有一题和本题很相似,脚本拿来修改一下
1 | from libnum import * |
flag: DDCTF{5x3ROxvqF2SJrDdVy73IADA04PxdLLab}
需要注意的是题目中提到了两个组织,我们需要对这两个组织分别解密,例如组织一的密文为
1 | [(1,0x30A152322E40EEE5933DE433C93827096D9EBF6F4FDADD48A18A8A8EB77B6680FE08B4176D8DCF0B6BF50000B74A8B8D572B253E63473A0916B69878A779946A)] |
解密得到
1 | 4470518445270315294253865008865808469591813925340527555511144870776210371333461962571100355988938503377974496098260851399298392762768768321710499151173494 |
以此类推,得到组织二
1 | 8941036890540630588507730017731616939183627850681055111022287516566391215447315659339930733926206804504075152291658988777248041197116052099144174634617967 |
然后利用密文
1 | pairs += [(1, 4470518445270315294253865008865808469591813925340527555511144870776210371333461962571100355988938503377974496098260851399298392762768768321710499151173494)] |
才能计算出 flag。
Upload-IMG
要求上传一个图片,并且里面要包含 phpinfo() 字符串,之前看到比较类似的题目,用脚本将字符串藏在图片中就可以。
1 | https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/ |
参考链接
1 | http://www.cnblogs.com/airobot/p/5303762.html |
Have Fun
JEB 分析,JAVA 层的代码好像经过混淆,大部分变量名和函数名都被替换成了特殊字符。找到了貌似是主要函数的位置
1 | private void key(String flag) { |
输入 flag 之后传入 enc 函数,这个函数又调用了 assert 中 dex 的代码。
(程序中的一些字符串经过加密,解密函数由于未知原因不能反编译,我编写了以下脚本对字符串解密)
1 | s = [46, -100, 13, -127, -18, 105] |
最后会传入 so 中进行对比验证,密文为
1 | @n|ixihPIppqws |
但是按照 dex 中的逻辑往回推算得到的字符串为
1 | ;huao_]D<baafa |
然而这个东西输入程序不正确。
静态分析到这里就走不下去了,于是采用动态分析的办法,用 android studio + xposed 拦截加密结果
1 | if ("com.didictf_2019.didicft2019_mobile".equals(loadPackageParam.packageName)) { |
例如,输入样例为 14 个 ‘a’,拦截到的加密结果为
1 | ihkjmlonqpsrut |
接着输入 14 个 ‘b’,得到解密结果
1 | jkhinolmrspqvw |
密文很有规律,尝试将它们分别与原文异或发现加密算法很简单,按位与 [8,9,10,11,12,13,14,15,16,17,18,19,20,21] 进行异或运算。
将原始密文异或上面的列表即可得到正确 flag。
flag: Hgvbtdf_Yabbcf
大吉大利,今晚吃鸡~
测试整数溢出,买票的时候抓包,修改票价为 4294967296,然后去支付页面购买。
买票之后要通过 id 和 ticket 移除对手,自己重新注册了一个账号可以成功移除,那么编写脚本批量注册账号移除对手就可以了(由于 id 的原因,移除的对手越多,移除的速度就越慢,所以需要多开几个脚本同时执行)。
1 | import requests |
flag: DDCTF{chiken_dinner_hyMCX[n47Fx)}
MulTzor
题目名字可能要表达 mult xor,即异或加密。
直接用 featherduster autopwn 一把梭。
1 | Cryptanalysis of the Enigma ciphering system enabled the western Allies in World War II to read substantial amounts of Morse-coded radio communications of the Axis powers that had been enciphered using Enigma machines. This yielded military intelligence which, along with that from other decrypted Axis radio and teleprinter transmissions, was given the codename Ultra. This was considered by western Supreme Allied Commander Dwight D. Eisenhower to have been "decisive" to the Allied victory. |
北京地铁
拿到题目分析图片,用 stegsolve 在低通道取出了一串 BASE64 编码的数据
1 | 7SsQWmZ524i/yVWoMeAIJA== |
用 BASE64 解不出来,猜想应该是还有另外的加密手段,于是用了各种工具测试图片,没有什么结果。
后续比赛放出最后一个提示,才知道密钥可能藏在内容里面,而不是隐写技巧。
仔细观察图片发现 2 号线魏公村点点颜色比较深,用字符串 weigongcun 作为密钥在线解密得到 flag
DDCTF{Q*2!x@B0}
- Title: DDCTF 2019
- Author: Catalpa
- Created at : 2019-04-18 00:00:00
- Updated at : 2024-10-17 08:47:27
- Link: https://wzt.ac.cn/2019/04/18/DDCTF2019/
- License: This work is licensed under CC BY-NC-SA 4.0.