Defcon 20 CTF Binary l33tness 300 Write up (b300)

By LittleFater

Defcon 20 CTF在半个小时前已经结束了,非常荣幸能和一群热衷技术并且充满激情朋友一起参加这次比赛,下面与大家分享一下b300的解题思路,希望下次有更多的朋友一起加入到比赛中来,让我们中国的参赛队能取得更好的名次。

b300的题目提供了两个文件,一个是后缀名为exe的文件,一个是后缀名为pcap的文件,如下图所示:

Pcap后缀的文件一般是网络数据包文件,我们可以用Wireshark打开,查看里面的内容,发现这只是一个单纯的TCP数据流,包含了TCP协议建立连接,发送数据和断开连接的过程,唯一比较特殊的地方,是其发送了10字节的数据,如下图所示:

现在我们可以大胆的猜想,这10个字节的内容,很可能与那个exe文件相关,于是我们将注意力放在了那个exe上面。但不幸的是,当用十六进制编辑器打开那个exe文件时,我们发现这根本不是我们所熟知的文件格式,如下图所示:

那这是一种什么格式的文件呢?通过用文件中存在的一些特殊字符串进行搜索,我们最终确定了这是一种名叫OpenVMS系统上的文件。OpenVMS是一种运行于VAX,Alpha或者Itanium架构的计算机上的系统(详细介绍看这里http://en.wikipedia.org/wiki/OpenVMS),也就是说这与我们熟悉的X86架构是截然不同的,也难怪文件结构看起来这么奇怪了。

要分析这种不常见的文件,首先就必须在短时间内熟悉它的运行的平台所使用的指令集,这是一个非常头疼的问题。但还有一个更为头疼的问题,就是要找到一种能够分析这种文件的反汇编工具。

但是非常幸运的是,Alpha指令集的文档还比较丰富和详尽,所以要快速的熟悉这种指令集并不是一件太困难的事。另外,强大IDA有对Alpha架构提供支持,所以解决这个问题的第一个关卡,算是成功攻破了。

接下来就是对文件的分析了,首先我要说一下怎么样让IDA加载这种文件,如果直接用IDA打开这个文件,IDA可能会错误地识别其文件类型为MS-DOS。因此,在加载文件之前,我们需要手动设置一下处理器类型,将其设置Alpha系列,另外还需注意一下,由于Alpha是64位架构的,所以应该使用64位的IDA,如下图所示:

能够得到反汇编代码,至少已经向成功迈进了很大一步,但是距离我们的终点,还有很长的距离。

接下来遇到的第一个问题,就是对函数的识别。根据IDA提供的反汇编代码,很多函数调用的地址已经在程序之外,与X86体系作类比,我们估计这些函数是系统调用,所以在这里我们无法准确的获取这些函数的具体功能,如下图所示:

无法准确获知函数的功能,使我们的分析陷入了僵局。但是,经过对题目的分析和理解,由于这是一道涉及网络通信的题目,而且程序里面也存在如下字符串:

所以我们再次大胆的推测,程序的流程就是一个典型的TCP通信模型,如下图所示:

因此,我们可以大致推测出其调用的函数的功能。我们假设程序的前面依次调用了socket、bind、listen函数,接下来,程序正好进入了一个循环,这个循环我们假设它是接收客户端的请求,然后处理数据的过程,那么它就应该调用accept、recv和send等函数。而从反汇编的代码来看,这个循环里面的结构与我们推测的结构非常吻合,而更令我们兴奋的是,在我们所推测的程序调用recv函数的地方,其刚好接收了10个字节的数据,然后对这10个数据进行了一个加密/解密操作,这和我们之前分析的pcap文件里面有10个字节的数据,完全一致!

这里简单提一下对这10个字节的处理方式,算法非常简单,就是利用了xor操作,下面这段代码是对其中一个字节的处理过程:

ROM:0000000000010854000 09 00 3D 2F     ldq_u   $25, 9($gp)     # 取出其中的一个字节放入$25寄存器

ROM:0000000000010858000 DA 00 38 4B     extbl   $25, $24, $26   # 将该字节扩展为64位存入$26寄存器

ROM:000000000001085C000 1A 08 52 47     xor     $26, $18, $26   # 将该字节与key进行异或

ROM:0000000000010860000 59 00 38 4B     mskbl   $25, $24, $25   # 将$25的低位清零

ROM:0000000000010868000 7A 01 58 4B     insbl   $26, $24, $26   # 将$26的高位清零

ROM:000000000001086C000 19 04 3A 47     or      $25, $26, $25   # $25 = $25 + $26

ROM:0000000000010870000 09 00 3D 3F     stq_u   $25, 9($gp)     # 将加密/解密后的字节存回原位

上面这段代码看起来比较复杂,但其实只执行了一个操作,那就是将该字节与key进行了一次异或操作,然后存回了原位置。

对其它几个字节的操作几乎完全一样,这里就不在复述。现在的问题是,异或所使用的key在哪里?

通过分析,我们发现,异或所需的key是通过一个函数调用获得的,但是非常遗憾的是,这个函数调用我们无法推断出其作用,其在代码中的位置如下图所示:

通过上述的分析,我们可以把加密/解密的算法总结一下。首先,我们发现key是一个Dword值,假设key是0x11223344,然后这个key将被拆分为四个字节0x11, 0x22, 0x33, 0x44,并按照下面的规律与那10个字节(0x16,0xfb, 0x86, 0x78, 0x3b, 0xd8, 0xa6, 0x35, 0x2d, 0x6e)进行异或运算:

密文:0x16  0xfb  0x86  0x78  0x3b  0xd8  0xa6  0x35  0x2d  0x6e

                                                    xor

密钥:0x11  0x22 0x33  0x44  0x44 0x33  0x22  0x11 0x11  0x44

但是就目前的分析结果来看,我们还获取不到key,看来这条路走不通了。那怎么办呢?在继续分析后面的代码后,我们发现程序后面还有一个验证循环,从这个验证循环中我们可以推断出这10个字节的最后一个字节是一个“!”:

根据前面所得到加密/解密算法,此时我们可以解出密钥的第四个字节的值应该为0x21 xor 0x6e = 0x4f,其中0x21时感叹号的ASCII码值,0x6e为最后一个字节。而10个字节的密文中有三个地方都用到了这个密钥字节进行解密,所以我们可以还原出明文为“X X X 7 t X X X X !”,其中X代表未知位。

但是现在也只能得到密钥的其中一个字节,其它位如何解密呢?我们再次陷入僵局。

转机再次到来,可能由于这道题长时间没有队伍完成吧,题目给出了新的提示:

One should ponderthe koan“What time is leet?”

这个提示初看没有什么特别的地方,似乎对这道题一点帮助都没有。但是这里有个关键字“leet”,leet是一种黑客语言(详细介绍看这里:http://en.wikipedia.org/wiki/Leet), 如果转换为数字的话,应该为1337,那这又有什么用呢?

我们再回头看一下我们已经得到的部分明文“X X X 7 t X X X X !”。没错,看到那个7了么?如果前面的四个明文刚好是1337,那么我们就可以据此得到这个Dword的key了,整个明文也就可以解出来了!

但是问题又来了,如果第一个字节是1的话,那么key的第一个字节就是0x31 xor 0x16 = 0x27,用这个key解密后面的字节时,会得到不可打印的ASCII字符,显然这是不正确的。

怎么办呢?就在这山重水复疑无路的时候,我突然发现了Binary类型题目的标题:Binary l33tness,没错!就是它,l33t!我们将1改成 l 结果会怎样呢?

不幸的是,依然是Wrong!就这样放弃了么?当然不行!如果l 不行,那 L 呢?

That’s right!

这道题的完成,除了技术方面的因素外,运气也占了很大的因素,不过Defcon的题目就是这样,不怕做不到,就怕想不到,希望以后有更多的朋友加入到我们的行列中来吧,通宵了一个晚上,思维比较混乱,可能写的不是很清楚,先回去睡觉去了。

最后非常感谢一起分析这道题的NWMonster大牛和Fish大牛,顺便和NWMonster大牛一起发发牢骚,下次出题能不能来点Windows平台的,不要这么非主流啊!(ps:这次的Binary题目没有Windows平台的)

  1. 同求 Windows 平台的 binary 题……

Leave a Comment



Verify Code   If you cannot see the CheckCode image,please refresh the page again!