-
-
[分享]pwn题Silence Serve
-
发表于:
2017-5-27 02:45
6214
-
一个不算是太难的pwn题吧。属于正常人类能做出来的题目范畴。
这一题的灵感来源于刚刚结束的DEF CON2017的mute和insanity两个题目。结合了这两个题目比较有趣的点之后写出了这题Silence Server。
Silence Server顾名思义,整个题目没有任何一句输出的代码,甚至使用了seccomp来禁用掉了包括write在内的绝大部分系统调用。因为seccomp对系统调用的禁用是不可能被取消的。所以即使能通过透漏控制程序执行或者拿到shell。也无法将flag输出回来。这个是这一题的比较坑人的地方。
下面是禁用syscall的代码。除了白名单中的10个系统调用之外,其他全部无法使用。
这个程序的主体部分是我自己实现的一个非常简单的基于栈的虚拟机。整个虚拟机只有17条指令。除了push_d指令之外的所有指令的操作数都是存放在一个栈中的。类似于x86上浮点指令的语法。当然和普通vm指令不同的一点是这个虚拟机是区分数据与索引的。对于纯粹的数据与索引有两套不同的字节码运算指令。我将64bit数据的最高位作为flag来区分数据与索引。最高位为1的数据将会被解释为索引类型,对这种类型的加减运算将会检查索引边界是否超过栈的范围(可以认为一个固定大小的栈是这个这个虚拟机的所有内存,不能索引超过栈内存的数据)。当然,程序的漏洞其实也就存于索引类型边界没有严格检查的地方。
下面是17个opcode的定义。行为根据名字应该就能猜到。
最后是程序的输入部分,为了不让程序的输入部分太过直白:) 而且也为了满足后续漏洞利用的一个重要条件。程序需要用户输入des加密过opcode和密钥。我写了一个8元一次方程组,输入的密钥必须是此方程组的解才能进行解密。当然,des不用静态编译肯定是不够意思的:)
为了能够输入数据,让虚拟机执行。首先要做的就是解8元一次方程组来获取密钥。方法和工具有很多z3,angr,matlab,python的数学库。即使是手算我想也不是很困难:-)
然后就是des加密和生成字节码的工作。des加密很简单,我用的是标准的DES-CBC。用python的Crypto库可以轻松加密。至于生成字节码,因为只有17个字节码而且几乎没有后继的立即数。所以直接写一个python字典来替换就可以了。
下面就是生成一个完整payload的代码
首先,这题我开启linux上的全部6种二进制漏洞保护:)所以普通的shellcode,栈溢出等是没法用的,而且mmap,mprotect等系统调用都被禁用了。
虚拟机中提供了load和store可以存取索引类型所引用的内存的功能。而且在load和store中其实是不检查索引类型是否越界的。对索引越界的检查全部都是放在索引类型写到栈上的时候。具体来说就是change_to_point,p_add,p_add这3个opcode中会检查。这样可以保证所有写入到栈上的索引类型不越界。程序的漏洞就在于,虚拟机使用的栈是存放在系统栈上的,而且在使用之前没有被初始化过。这样我们可以通过编排数据,来在未初始化的虚拟机栈上构造出一个越界的指针。这样使用load和store来索引的时候就会产生一个越界的读写。从而控制返回值。
首先是如何在虚拟中栈上构造越界的索引。在getCode函数中,输入的加密数据也是储存在栈上的。所以只要在加密数据之后构造就可以了。而且opcode中有stop这个指令,所以不用担心解密出来的错误code。这样就可以在runCode的虚拟机栈上构造出一个越界的索引了。当然,具体的偏移需要好好算一算
然后是pie/aslr绕过。因为aslr和pie的关系。内存中的地址都是随机的。因为没有输出,所以没有办法leak地址。不过只要将返回值读取进来,直接写字节码来对返回地址加减偏移,再将算好的地址写回去。这样就可以在不leak的情况下调用任意的libc函数以及rop了。
下面是读取并计算libc以及程序加载基地址,并且储存在栈最低位的代码
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)