Skip to content

Pwnable.kr echo2

复制本地路径 | 在线编辑

源代码漏洞

简化后的代码如下,程序可以无限选择执行 echo2echo3cleanup 函数。直接说漏洞点:很明显 echo2 有 FSB 漏洞, echo3 加上 cleanup 有 UAF 漏洞。

__int64 echo2()
{
  char format; // [rsp+0h] [rbp-20h]

  (*((void (__fastcall **)(void *))o + 3))(o);
  get_input(&format, 32);
  printf(&format, 32LL);
  (*((void (__fastcall **)(void *))o + 4))(o);
  return 0LL;
}

__int64 echo3()
{
  char *s; // ST08_8

  (*((void (__fastcall **)(void *))o + 3))(o);
  s = (char *)malloc(0x20uLL);
  get_input(s, 32);
  puts(s);
  free(s);
  (*((void (__fastcall **)(void *, signed __int64))o + 4))(o, 32LL);
  return 0LL;
}

void cleanup() { free(o); }

int main(int argc, const char **argv, const char **envp)
{
  unsigned int choice; // [rsp+Ch] [rbp-24h]
  __int64 v7; // [rsp+10h] [rbp-20h]
  __int64 v8; // [rsp+18h] [rbp-18h]
  __int64 v9; // [rsp+20h] [rbp-10h]

  printf("hey, what's your name? : ", 0LL);
  __isoc99_scanf("%24s", &v7);

  o = malloc(0x28uLL);
  *((_QWORD *)o + 0) = v7;
  *((_QWORD *)o + 1) = v8;
  *((_QWORD *)o + 2) = v9;
  *((_QWORD *)o + 3) = greetings;
  *((_QWORD *)o + 4) = byebye;

  getchar();
  func[0] = (__int64)echo1;
  func[1] = (__int64)echo2;
  func[2] = (__int64)echo3;
  do {
    while ( 1 )
    {
        puts("\n- select echo type -");
        puts("- 1. : BOF echo");
        puts("- 2. : FSB echo");
        puts("- 3. : UAF echo");
        puts("- 4. : exit");
        __isoc99_scanf("%d", &choice);
        getchar();
        ((void (__fastcall *)(const char *, unsigned int *))func[choice - 1])("%d", &choice);
        puts("invalid menu");
    }
    cleanup();
    printf("Are you sure you want to exit? (y/n)");
    choice = getchar();
  } while ( choice != 121 );
  return 0;
}

别人的做法

这道题其实很简单很简单,流程如下。

  1. 首先通过 echo2 泄露 ebp 的地址,从而可以计算出 name 的地址,这个 name 是我们事先输入的 shellcode
  2. 然后执行 4. exit ,从而触发一个 cleanup 函数,从而会把 o 这个 0x20 大小的变量 free 掉。
  3. 最后执行 echo3 ,导致申请的 s 就是之前释放的 o ,因此可以改变 o + 4name 地址,这样执行 o + 4 ,就相当于执行了 name ,即我们事先输入的 shellcode

我的做法

我这个做法有点硬核了,竟然直接通过 FSB 暴力做出来了,下面来详细讲一讲。

  1. 同样, name 需要输入可以执行的 shellcode
  2. 同样, 利用 echo2 泄露 o 的内容。其中 o 是在 BSS 段上的变量,地址是 0x602098,里面存的 malloc 指针。
    # o = malloc(0x28uLL);
    '%8$s' + 'aaaa' + p64(o_addr)
    

2.1 分析上面的泄露,主要在于使用了 %s,因此这次泄露我们可以获得 o 的内容,也就是那个 malloc 指针。
一定要分清楚,上面这条语句输出的就是那个指针的地址,而不是 name + greetings + byebye.

scanf("%24s", &v7); // v7, v8, v9
*((*QWORD)o + 0) = v7; *((*QWORD)o + 1) = v8; *((*QWORD)o + 2) = v9;
*((*QWORD)o + 3) = greetings;
*((*QWORD)o + 4) = byebye;

2.2 假设这个指针是 heap_addr,那么很显然,构造结构是这样的。
heap_addr + 0x00 --> [ name ]
heap_addr + 0x18 --> [ greetings ]
heap_addr + 0x20 --> [ byebye ]

  1. 最后,把 byebye_ptr 改成 name_addr,泄露格式如下。
    padding = ('%' + str(heap_addr) + 'c%8$n').ljust(16, 'a')
    padding = (padding + p64(heap_addr + 0x20))
    

总结

很不错的小题,总结的话确实不知道怎么归类,可以回顾回顾看看,不费多长时间。