Preface
这个比赛的时候压根没看到。。
check
先看下基本信息
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX disabled
PIE: No PIE
32bit,got可覆盖'
Analysis
程序分为几个步骤
- 通过clone调用fn函数在子进程中运行,父进程则通过waitpid等待子进程执行结束
- 子进程又切换到jail目录下,然后又fork了个子进程,接下去调用chroot函数,接下去才调用真正的执行主要的函数
- vuln_main中首先调用函数取读两个文件,作为之后调用syscall的函数表来查看,并且两个文件对应x86和x64。在后面实际上x86提供的函数后面会给我们输入来进行调用
- 打印操作表,接受并执行相关操作
function list
主要有5个操作
set_syscall
获取syscall调用表到804E184(标记为tmp_syscall_ptr)
add_syscall
添加syscall。
- 读取名字,标号,参数个数
- 循环读取参数个数存放到结构体当中
- 修改804E174(s_e_sycall)中存放的syscall列表起始和结尾指针
有一个地方有点难理解,要分析和猜到或者调试了之后,知道程序结构之后才好理解,这里实际上就是对一个list的结尾指针进行操作,
call_syscall
.rodata:0804B4E0 off_804B4E0 dd offset ___cxa_pure_virtual
利用上面的函数进行实际函数调用。下面分析的struct中第一个就是
剩下的操作很简单了,pass
struct
主要有两个结构
struct rodata_804E174 // x86 syscall table
{
struct *start;
struct *end;
};
上面这个结构主要指向一个列表,列表里存的也是指针(有点像函数列表),每个指针指向下面这个结构体
struct sys_code
{
uint4 rodata_804B4E0; // 0 cxa_pure_virtual
uint4 rodata_804E164; // x64 or check overflow
char *name; // 8
uint4 *rax; // 12
uint4 *rbx;
uint4 *rcx;
uint4 *rdx;
uint4 *rsi;
uint4 *rdi;
uint4 *r9??; // 40+(-1)*4
char *number; // 40+0*4
char *arg1; // 40+1*4
};
分析了挺久,主要是要结合具体的程序执行来分析比较方便
Vuln
整数溢出是很明显的
这里判断v5<=6,如果输入负数实际上就能绕过,接下来再输入 < v5的负数就行了。
这里是对struct sys_code中的argv进行添加,刚刚输入的arg index就是这里标的i,而再看看sys code 结构,控制i为负数就能覆盖到结构体前面的各个变量和参数了,不过要主要不能覆盖rodata_804E164,因为程序中好像有检查。这里很明显可以覆盖rodata_804B4E0,因为程序在后面call sys的时候就是调用其指向的rodata指向的函数。(rodata不可写,这里覆盖的是指针,所以是可以的)
Leak
具体如何覆盖的话,可以先试试。。具体的整个程序中的结构如下
0x0804E168 ------------------- -------------------
0 start_ptr ----------> | sys_code[0] |------> 0 | rodata_804B4E0 |
4 end ptr / ------------------- -------------------
----/ | sys_code[1] | 4 | rodata_804E164 |
/ ------------------- ------------------- --------------------
| | sys_code[2] | 8 | *name_ptr |------>| string 'df..' |
| ------------------ ------------------- --------------------
| | sys_code[3] | C | *eax_ptr | -----\
| ------------------- -------------------- \ --------------
tmp_syscall_ptr | .省略几个. | \--> | '???'' |
-------------------- --------------
40 | *number |
--------------------
44 | *arg1 |
-------------------
当调用第一个函数的时候,tmp_syscall_ptr就如图,指向第一个syscode块的指针,如果把rodata_804B4E0覆盖为plt.puts,那么puts就会输出sys code[0]的堆地址了!