网络安全日CTF

4.29是首都网络安全日,除安全厂商参展炫技外,还有近70支来路各异的队伍前来参加为期一天的CTF攻防赛事。比赛分为上午和下午两个场次,各3个小时,中间不到一小时的休息时间。上午的比赛内容为线上答题,题目种类包含 Misc,Pwn,Web,Crypto,Reverse五个类别。相比下午的攻防夺旗赛,上午的题目和我平日研究的内容更贴近,因而投入了更多的精力。

上午的比赛,每一道题目的答案都以flag形式出现,通常是一个可以明辨含义的单词或其MD5散列,提交到在线答题系统即可得分,各个队伍的总分实时更新显示在题目侧边。赛程只有三个小时,遗憾的是很多复杂的题目连上手分析的机会都没有,庆幸的是有限时间减轻了精神压力,否则再多几个小时的头脑风暴可能就体力不支了。

Crypto

顾名思义,这类题目主要考察密码分析学的知识。和其他类别一样,每道题目都是自成一篇微小说,描绘了一个历史人物的经典剪辑或是谍战风云的早木皆兵。不难看出题目背后的用心雕琢,力图少几分枯燥,多些娱乐。比如第一道题目即是凯撒大帝经典的移位密码,出题者选择了13作为加密秘钥,刚好是26的一半,意味着利用加密算法穷举到秘钥后不用再绞尽脑汁算解密秘钥,而是再次加密就得到明文。

还有一道题目讲述了一个谍战中通过音乐传递情报的故事,并附上乐谱,要求从中还原明文,如图所示:

比赛时并没能参透,匆匆浏览只注意了数字。赛后后发现歌词原来也是提示,充满了浪漫的小趣味,用八进制格式化音符再转成asc码就是答案ILoveSecurityVeryMuch。

Pwn

这类题目没有太多变数,一般通过溢出漏洞让目标程序做些预期外的事儿。通常先给出Linux下跑的程序,只要分析清楚,写好利用代码,然后向指定服务器发包获得权限就能拿到flag文件。

第一题是在比赛中做出来的题目,还比较简单,只要用超长数据覆盖掉指定变量就能让程序流程改变输出flag信息了。

第二题就困难了一大截,程序运行后包含三次scanf输入,前两次输入都有strlen验证输入长度(可以使用0x00填充绕过长度限制),第三次的输入的内容虽然没有长度验证,但会被预定字串I_Need_BMW异或变换。如果变换后的字串和The_Pursuit_of_Happiness相同则会跳转到该字串起始位置开始执行。

虽然程序sub_804859C函数的溢出点很容易发现,且编译时关闭了ASLR和DEP,加之利用三次输入可以进行栈溢出覆盖返回值,但问题是整个程序空间都定位不到jmp esp类的指令用以跳向shellcode。考虑到题目特意包含了第三次输入内容经变换就可被跳转执行,溢出的思路也开阔了不少。

利用过程要触发两次溢出,第一次溢出覆盖ebp为I_Need_BMW等常量所在内存地址附近(不开ASLR时这个地址固定),然后返回值覆盖为sub_804859C起始位置sub esp, 168h的位置,如图所示:

溢出使得程序随后跳转到sub esp, 168h位置,保证ebp指向常量内存空间

这样第一轮溢出后程序会再执行一轮三次scanf,通过前两次输入中注入大量0x00触发第二次溢出,清空秘钥I_Need_BMW和比对明文The_Pursuit_of_Happiness,使得注入的shellcode不会因为异或有过大改动,只要提前反变换shellcode就可以使得变换后仍然不丢失语义。这样第二轮执行后,末尾会跳转到第三次输入的内容作为代码执行。

Reverse

这部分题目比较灵活,除对二进制程序的逆向分析外,还包含很多结合近年热门的解固件的问题。其中一道题目就是给了路由器的固件,要求分析出当中的后门反向连接的地址信息。虽然看过使用binwalk解包的案例分析,但真正拿到固件包时仍心有余而力不足。第一重解出来一堆zlib和squashfs,和心理预期的文件系统样式不符就停滞不前了。这部分题目要么是简单到分析过后就没有印象,要不就是思路上走不通只好放下。

下午的攻防实战环节还有一道比较难的逆向题目,需要分析一个放大镜后门程序的登录口令。一旦输入正确的口令,程序会弹出资源管理器,这样就能绕过远程桌面认证输入直接渗透进入目标主机了

首先这个看似轻巧的后门包含多种反调试陷门,由于平时分析漏洞多用Immunity Debugger,缺少反反调试的插件,只好用IDA纯静态查看。其次,程序内的函数调用逻辑十分抽象,关键算法都是数十个虚函数的嵌套迭代,用静态分析的方法十分吃亏。赛后求助同事老唐,花了一天时间才了解了背后的蹊跷。

它极可能使用易语言完成了开发,因而程序逻辑不像C语言一样明晰。此外程序中还包含一个陷阱,如果通过URLDecode可以很容易解出来一个口令HXB{YAO-YAO-QIE-KE-NAO},点击登入甚至会弹出添加系统管理员账户的界面,并且IDA上下文内包含net user /add等字样,迷惑程度异常高。

最后用包含反反调试插件的OllyDbg跟踪到了真正的加密函数入口,输入的信息被加密后需要和另一个URLEncode的字串相同才可以。加密算法形似RC4,但部分结构被篡改,使用RC4算法并不能解出来真实口令。一个取巧的办法是在加密入口强制修改内存,将输入数据修改为URLEncode字串,查看加密出口时的内存就能发现真实口令HXB{HAHA-HEHE-HEIHEI-HUOHUO-XIXI}赫然出现了。

Misc

杂项题目就很丰富了,可能综合运用到其他题目的技术,并且包含很多有趣的彩蛋。其中一道题目是叙述了一个谍影重重的案件,高潮迭起的故事结尾,间谍U盘镜像落入囊中。镜像解开后,里面包含了很多映射故事中点滴线索的文档

其中systemzx.exe是关键的程序,执行后会释放机密的flag文件,但提示身份验证失败,flag又被删除。题目本意肯定是希望逆向systemzx.exe后找到应该输入的信息,让解压后身份审核通过,flag文件得以保留。

但实际操作中发现再次执行,由于解压缩的覆盖操作需要用户确认,解压执行流程被暂停,flag文件还未被删除,拷出来后执行就得到了隐藏的机密文件。这种彩蛋式的解法让人有种捡了钱的幻觉。

纵观上午的赛事,题目的设计真是用尽了心思,即保证三个小时各队都能有所收获,也有一定难度可以拉开差距,甚至赛后留给大家意犹未尽的味道。

 

Tagged , . Bookmark the permalink.

2 Responses to 网络安全日CTF

  1. czy says:

    哈哈,前几天我也遇到你说的逆向放大镜的题了,交流下
    前几天第一次参加CTF,遇到个比较有意思的逆向题,题目是要你分析一个易语言写的
    方大镜后门程序,找到密码。

    先用UE打开exe文件,以二进制方式查看能发现如下内容
    00071200h: 00 00 00 30 40 25 34 38 25 35 38 25 34 32 25 37 ; …0@%48%58%42%7
    00071210h: 42 25 35 39 25 34 31 25 34 46 25 32 44 25 35 39 ; B%59%41%4F%2D%59
    00071220h: 25 34 31 25 34 46 25 32 44 25 35 31 25 34 39 25 ; %41%4F%2D%51%49%
    00071230h: 34 35 25 32 44 25 34 42 25 34 35 25 32 44 25 34 ; 45%2D%4B%45%2D%4
    00071240h: 45 25 34 31 25 34 46 25 37 44 00 30 00 20 2F 61 ; E%41%4F%7D.0. /a
    00071250h: 64 64 00 20 00 6E 65 74 20 75 73 65 72 20 00 6E ; dd. .net user .n
    00071260h: 65 74 20 6C 6F 63 61 6C 67 72 6F 75 70 20 61 64 ; et localgroup ad
    00071270h: 6D 69 6E 69 73 74 72 61 74 6F 72 73 20 00 48 49 ; ministrators .HI
    00071280h: A3 BA 00 D5 CB BA C5 CC ED BC D3 B3 C9 B9 A6 A3 ; :.账号添加成功?
    00071290h: A1 00 2D 00 33 38 2D 33 38 2D 32 43 2D 33 36 2D ; ?-.38-38-2C-36-
    000712a0h: 34 32 2D 32 43 2D 33 34 2D 33 35 2D 32 43 2D 33 ; 42-2C-34-35-2C-3
    000712b0h: 34 2D 34 35 2D 32 43 2D 33 39 2D 34 36 2D 32 43 ; 4-45-2C-39-46-2C
    000712c0h: 2D 34 34 2D 33 36 2D 32 43 2D 34 31 2D 34 36 2D ; -44-36-2C-41-46-
    000712d0h: 32 43 2D 33 35 2D 33 31 2D 32 43 2D 33 38 2D 34 ; 2C-35-31-2C-38-4

    初步判断这些数据是找出明文密码的关键点。
    将最前面的%48%58%42%7B%59%41%4F%2D%59%41%4F%2D%51%49%45%2D%4B%45%2D%4E%41%4F%7D
    用URLDCODE方式解码出来是字符串HXB{YAO-YAO-QIE-KE-NAO},感觉象密码,一测试发现程序
    虽然能弹出添加用户的框,但是无法成功添加用户,原来这只是个坑。

    猜测下面一点的38-38-2C….长串或者再下面一点的
    000713b0h: 2D 32 43 2D 34 34 2D 33 36 2D 32 43 00 35 32 2C ; -2C-44-36-2C.52,
    000713c0h: 42 31 2C 33 36 2C 32 30 2C 44 30 2C 46 32 2C 33 ; B1,36,20,D0,F2,3
    000713d0h: 33 2C 41 44 2C 43 44 2C 44 37 2C 45 45 2C 34 30 ; 3,AD,CD,D7,EE,40
    000713e0h: 2C 34 30 2C 35 42 2C 31 34 2C 44 37 2C 31 36 2C ; ,40,5B,14,D7,16,
    000713f0h: 35 30 2C 43 42 2C 34 41 2C 44 34 2C 45 34 2C 45 ; 50,CB,4A,D4,E4,E
    00071400h: 45 2C 00 35 39 2C 44 33 2C 32 38 2C 30 43 2C 45 ; E,.59,D3,28,0C,E
    00071410h: 30 2C 44 44 2C 31 38 2C 45 46 2C 45 33 2C 45 35 ; 0,DD,18,EF,E3,E5
    00071420h: 2C 46 44 2C 30 38 2C 36 39 2C 36 32 2C 33 44 2C ; ,FD,08,69,62,3D,
    00071430h: 39 35 2C 32 46 2C 37 30 2C 39 34 2C 32 41 2C 46 ; 95,2F,70,94,2A,F
    00071440h: 30 2C 44 33 2C 46 36 2C 00 2C 00 31 00 32 00 33 ; 0,D3,F6,.,.1.2.3
    可能是真实密码

    然后IDA动态调试该EXE,经查找上述几处字符的引用函数是004037A4。在这个函数处下断
    果然每次输完密码点OK都会在这儿被拦下。
    快速对该函数进行分析发现该函数开头有VmprotectBeg_2 db ‘VMProtect begin’,0
    字样,但其实该函数并没有被VMP保护。
    进一步分析在
    00403876 call sub_403BCF ; 这儿会把38-38-2C….长串中的-转换为%
    然后在
    00403986 call chghash4027F3 ;这儿会把上面的长串转成一个33字节的HASH
    转换后的值为
    005EBF88 38 38 2C 36 42 2C 34 35 2C 34 45 2C 39 46 2C 44 88,6B,45,4E,9F,D
    005EBF98 36 2C 41 46 2C 35 31 2C 38 46 2C 45 37 2C 39 33 6,AF,51,8F,E7,93
    005EBFA8 2C 31 36 2C 38 38 2C 44 33 2C 30 43 2C 41 30 2C ,16,88,D3,0C,A0,
    005EBFB8 33 44 2C 34 35 2C 36 37 2C 33 44 2C 33 33 2C 38 3D,45,67,3D,33,8
    005EBFC8 37 2C 43 44 2C 42 34 2C 31 41 2C 31 41 2C 32 34 7,CD,B4,1A,1A,24
    005EBFD8 2C 44 37 2C 44 31 2C 44 39 2C 41 30 2C 42 41 2C ,D7,D1,D9,A0,BA,
    005EBFE8 44 36 2C 00 AB AB AB AB AB AB AB AB EE FE EE FE D6,.铪铪

    其实转换方式就是两个ASCII码合成一个16进制中间2C直接转为,号
    然后在下面一点的
    004039EA call mkpass404196 ; 这儿会将我们输入的明文密码加密为一个HASH
    其中第二个参数应该是加密密钥,值为字符串19980101
    然后在下面一点的
    .text:00403A12 mov eax, [ebp+var_4]
    .text:00403A15 push eax ; 原HASH
    .text:00403A16 push [ebp+var_10] ; 我的输入串的HASH
    .text:00403A19 call cmphash401004
    是关键的比较,这儿会比较上述两个HASH是否相同,强制修改返回值EAX,会
    发现接下来的流层中程序会用偏移000713bd处的那个HASH(52,B1,36,20,D0,F2,33,AD,CD,D7,EE,40,40…..)
    解出来是一个23字节的字符串c:windowsexplorer.exe,然后运行explorer

    如果HASH不相同,则会用偏移00071403处的HASH(59,D3,28,0C,E0,DD,18,EF,E3,E5,FD,08,69,….)
    解出来那个假密码HXB{YAO-YAO-QIE-KE-NAO},然后直接比较明文是否是这个如果是这个
    就弹出添加用户的框(但没有具体的加账号的代码这儿很骗人),如果不是则退出函数。

    通过前面的分析整个程序基本流层就清楚了,那么解题关键就是
    如何让我们输入的明文经过
    .text:004039E0 push 1
    .text:004039E2 lea eax, [ebp+var_8] ; 估计是加密密钥:19980101
    .text:004039E5 push eax
    .text:004039E6 lea eax, [ebp+var_C]
    .text:004039E9 push eax
    .text:004039EA call mkpass404196 ; 将密码转成HASH
    这儿的运算得出的HASH要是88,6B,45,4E,9F,D6,AF,51,8F,E7,93,16,88,D3,0C,A0,3D,45,67,3D,33,87,CD,B4,1A,1A,24,D7,D1,D9,A0,BA,D6

    简单输入123或者123456之类的明文发现转出来的HASH和明文长度是相同的,还好这样的话就不会是MD5,SHA1之类的
    摘要算法(如果是摘要算法要么无解要么还要跑密码,难度应该没这么大),而且还有个可疑的参数是19980101,那么多半是rc之类的
    对称加密。对称加密通常会是通过一个密钥生成一定长度的乱数,然后用明文与乱数做XOR之类的运算得出密文。现在我们已经有密钥
    和密文了,那么反解理论上肯定是OK的。
    然后在动态调试程序的时候,动态修改内存将输入的明文改为
    88,6B,45,4E,9F,D6,AF,51,8F,E7,93,16,88,D3,0C,A0,3D,45,67,3D,33,87,CD,B4,1A,1A,24,D7,D1,D9,A0,BA,D6
    然后一看返回值果然是字符串:HXB{HAHA-HEHE-HEIHEI-HUOHUO-XIXI}
    明文输入这个和假密码类似的串,成功运行explorer,解题成功!

    后记:做这个题刚开始在GetWindowText函数下断一直不对,在假密码处也差点被坑死,时间有限
    搞得很紧张,前后花了3个小时,回家后很轻松的在1小时之内搞定,看来CTF这种不止是考技术水平,
    更多的是心理素质。

    • hhjack says:

      咱俩解法差不多,我花了一天时间才找出来~~也是把这段密文替换到加密函数的内存中,然后在加密后,就看到明文了~~~
      这道题我以为是这个4.29原创的呢,现在看来还真不一定呢,你这又遇到了一次,可能此前也多次出现的题目。不过设计的真实挺精巧~

发表评论

电子邮件地址不会被公开。 必填项已用*标注