今天突然发现看雪多了一个pwn的版块,于是想把自己前段时间刚做的一道题拿出来和大家分享,也支持一下新版块:)大牛还请轻拍~
题目为pwnable.kr的ascii,难度为Grotesque
首先看一下IDA对main函数的反汇编结果:
int __cdecl main(int argc, const char **argv, const char **envp)
{
_BYTE *v3; // ebx
char v5; // [esp+4h] [ebp-30h]
int v6; // [esp+28h] [ebp-Ch]
unsigned int v7; // [esp+2Ch] [ebp-8h]
v6 = mmap(0x80000000, 4096, 7, 50, 0xFFFFFFFF, 0);
if ( v6 != 0x80000000 )
{
puts("mmap failed. tell admin");
exit(1);
}
printf("Input text : ", v5);
v7 = 0;
do
{
if ( v7 > 399 )
break;
v3 = (_BYTE *)(v6 + v7);
*v3 = getchar();
++v7;
}
while ( is_ascii((char)*v3) );
puts("triggering bug...");
return vuln();
}
main函数大致做了这么几件事:
1、mmap了一块堆内存,起始地址为0x80000000,用于保存从stdin读入用户输入的内容
2、对用户输入的字符串内容检查:用户输入的每个字符都应该为可见字符(否则就截断字符串),即ASCII值范围为[ 0x20 , 0x7E ]
3、对用户输入的字符串长度检查:长度应小于400(这点其实对本题影响不大)
4、调用vuln函数,将用户输入的内容(保存于0x80000000)复制到vuln函数的本地变量上面,从而造成栈溢出
检查一下binary的各种安全参数,情况如下:
[*] '/home/zero/Desktop/ascii/ascii'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
而且由于最终该binary是要在服务端运行的,而服务端又开启了ASLR,所以vdso段是随机化的。
该题目网上已经有公开的解决方法,但是该公开方法已经无效,所以在这里我写一下如果想用新的方法需要注意的点:
问题1、网上公开的那种ROP方式已经不能再用,因为需要从vdso段中获取的ROP Gadget地址和内容都发生了变化,所以ROP Gadget是需要变化的
问题2、公开方法中提到的使用"ulimit -s unlimited"(CVE-2016-3672)漏洞方式使vdso基地址固定,然后再用硬编码的方式将ROP Gadget通过栈溢出写入栈中,但是pwnable.kr已经修补了该漏洞,所以用这种方式固定vdso段地址也失效了
问题1比较好解决,因为是vdso段的信息发生了变化导致了Gadget信息也发生了改变,所以只要再从现在的vdso中重新查询可利用的Gadget即可(这里有一个扣题ascii的小坑,留给大家自己做一遍发现,嘿嘿),只要具体的ROP Chain大家可以自己去动手构造,并不难:)
我最终使用的两条ROP Gadget分别为0xC75和0xC78:
gdb-peda$ vmmap vdso
Start End Perm Name
0x555fa000 0x555fc000 r-xp [vdso]
gdb-peda$ x/3i 0x555fa000+0xc75
0x555fac75 <__vdso_time+37>: pop ebx
0x555fac76 <__vdso_time+38>: pop ebp
0x555fac77 <__vdso_time+39>: ret
gdb-peda$ x/2i 0x555fa000+0xc78
0x555fac78: mov eax,DWORD PTR [esp]
0x555fac7b: ret
gdb-peda$
问题2是本道题目的解决关键,我在解决的时候实际上只要一直爆破就可以了
当然本题的一个重要考察点为Alphanumeric Encode,这点网上已经有很多文章介绍,所以这里不再赘述。
考虑到pwnable.kr官网的要求(Rules & Tips中的第3点),所以在这里我不会提供Solver的源码。
其实这道题写出Solver并不难,自己动手做出来才是真的懂,对吧:)
贴一张我最后解决该问题的截图,实测我最少需要爆破10+次,最多需要爆破300+次即可爆破成功。
附:网上公开的解决方法(公开方法中的exp如果直接使用应该是失效的,但是可以作为参考):
1、http://www.mottoin.com/87792.html
2、http://www.lovekira.cn/?p=340
首先看一下IDA对main函数的反汇编结果:
int __cdecl main(int argc, const char **argv, const char **envp)
{
_BYTE *v3; // ebx
char v5; // [esp+4h] [ebp-30h]
int v6; // [esp+28h] [ebp-Ch]
unsigned int v7; // [esp+2Ch] [ebp-8h]
v6 = mmap(0x80000000, 4096, 7, 50, 0xFFFFFFFF, 0);
if ( v6 != 0x80000000 )
{
puts("mmap failed. tell admin");
exit(1);
}
printf("Input text : ", v5);
v7 = 0;
do
{
if ( v7 > 399 )
break;
v3 = (_BYTE *)(v6 + v7);
*v3 = getchar();
++v7;
}
while ( is_ascii((char)*v3) );
puts("triggering bug...");
return vuln();
}
main函数大致做了这么几件事:
1、mmap了一块堆内存,起始地址为0x80000000,用于保存从stdin读入用户输入的内容
2、对用户输入的字符串内容检查:用户输入的每个字符都应该为可见字符(否则就截断字符串),即ASCII值范围为[ 0x20 , 0x7E ]
3、对用户输入的字符串长度检查:长度应小于400(这点其实对本题影响不大)
4、调用vuln函数,将用户输入的内容(保存于0x80000000)复制到vuln函数的本地变量上面,从而造成栈溢出
检查一下binary的各种安全参数,情况如下:
[*] '/home/zero/Desktop/ascii/ascii'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
而且由于最终该binary是要在服务端运行的,而服务端又开启了ASLR,所以vdso段是随机化的。
int __cdecl main(int argc, const char **argv, const char **envp)
{
_BYTE *v3; // ebx
char v5; // [esp+4h] [ebp-30h]
int v6; // [esp+28h] [ebp-Ch]
unsigned int v7; // [esp+2Ch] [ebp-8h]
v6 = mmap(0x80000000, 4096, 7, 50, 0xFFFFFFFF, 0);
if ( v6 != 0x80000000 )
{
puts("mmap failed. tell admin");
exit(1);
}
printf("Input text : ", v5);
v7 = 0;
do
{
if ( v7 > 399 )
break;
v3 = (_BYTE *)(v6 + v7);
*v3 = getchar();
++v7;
}
while ( is_ascii((char)*v3) );
puts("triggering bug...");
return vuln();
}
main函数大致做了这么几件事:
1、mmap了一块堆内存,起始地址为0x80000000,用于保存从stdin读入用户输入的内容
2、对用户输入的字符串内容检查:用户输入的每个字符都应该为可见字符(否则就截断字符串),即ASCII值范围为[ 0x20 , 0x7E ]
3、对用户输入的字符串长度检查:长度应小于400(这点其实对本题影响不大)
4、调用vuln函数,将用户输入的内容(保存于0x80000000)复制到vuln函数的本地变量上面,从而造成栈溢出
检查一下binary的各种安全参数,情况如下:
[*] '/home/zero/Desktop/ascii/ascii'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
[*] '/home/zero/Desktop/ascii/ascii'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
该题目网上已经有公开的解决方法,但是该公开方法已经无效,所以在这里我写一下如果想用新的方法需要注意的点:
问题1、网上公开的那种ROP方式已经不能再用,因为需要从vdso段中获取的ROP Gadget地址和内容都发生了变化,所以ROP Gadget是需要变化的
问题2、公开方法中提到的使用"ulimit -s unlimited"(CVE-2016-3672)漏洞方式使vdso基地址固定,然后再用硬编码的方式将ROP Gadget通过栈溢出写入栈中,但是pwnable.kr已经修补了该漏洞,所以用这种方式固定vdso段地址也失效了
问题1比较好解决,因为是vdso段的信息发生了变化导致了Gadget信息也发生了改变,所以只要再从现在的vdso中重新查询可利用的Gadget即可(这里有一个扣题ascii的小坑,留给大家自己做一遍发现,嘿嘿),只要具体的ROP Chain大家可以自己去动手构造,并不难:)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)