← Back to Writeups
HTBN/AReversing

Rega's Town

XESXOR8/23/20266 min read
#reversing#htb#n/a

Rega's Town

Platform: HackTheBox | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-02-28 | Status: Solved Techniques: regex_constraint_extraction, position_constraint_mapping, ascii_product_verification, string_analysis, leetspeak_decoding

Summary

ELF 64-bit LSB PIE executable, x86-64, dynamically linked, not stripped, with debug info. Rust binary rega_town (~19MB, typical for Rust). The program asks for a "secret passphrase" and validates input in two stages: first through 9 regex patterns, then through ASCII code product verification of s

Recon

Port scan

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

Enumeration highlights

  • Event: HackTheBox | ID: 20260228_hackthebox_regas_town
  • Tags: elf64, leetspeak, regex, constraint_satisfaction, rust, ascii_arithmetic, string_validation
  • Indicators: Rust binary with regex crate, embedded POSIX regex patterns in strings output, challenge name hints at regex (Rega = Regex), multi-stage input validation: regex + arithmetic check, character product comparison using u128 arithmetic
  • Source: 20260228_hackthebox_regas_town.md

Foothold

Vulnerability / Misconfiguration

  1. Regex_constraint_extraction
  2. Position_constraint_mapping
  3. Ascii_product_verification
  4. String_analysis
  5. Leetspeak_decoding
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

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.
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • regex_constraint_extraction
  • position_constraint_mapping
  • ascii_product_verification
  • string_analysis
  • leetspeak_decoding
  • Tags: elf64, leetspeak, regex, constraint_satisfaction, rust, ascii_arithmetic, string_validation

Original Writeup

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

Description

Welcome to Rega Town, a quaint little place where everyone communicates through the magic of patterns and rules!

ELF 64-bit LSB PIE executable, x86-64, dynamically linked, not stripped, with debug info. Rust binary rega_town (~19MB, typical for Rust). The program asks for a "secret passphrase" and validates input in two stages: first through 9 regex patterns, then through ASCII code product verification of substrings.

Analysis

Initial Reconnaissance

$ file rega_town
ELF 64-bit LSB PIE executable, x86-64, dynamically linked, with debug_info, not stripped

$ strings rega_town | grep -E "Welcome|passphrase|secret"
Welcome to our secret town!
Enter secret passphrase:

The binary is not stripped and contains debug info — Rust symbols are fully available for analysis.

Key Functions

rega_town::main         @ 0x58230 — entry point, prints greeting, reads input
rega_town::filter_input @ 0x578f0 — validation through 9 regex patterns
rega_town::check_input  @ 0x57c00 — extracts substrings, verifies ASCII code products
rega_town::multiply_characters @ 0x57bd0 — computes product of ASCII values (u128)

Stage 1: Extracting Regex Patterns

Running strings on the binary revealed a block of 9 POSIX-style regex patterns located between called Result::unwrap() on an Err value and src/main.rs:

#RegexConstraint
1^.{33}$String length = 33 characters
2(?:^[\x48][\x54][\x42]).*Starts with "HTB" (0x48=H, 0x54=T, 0x42=B)
3^.{3}(\x7b).*(\x7d)$Position 3 = { (0x7b), ends with } (0x7d)
4^[[:upper:]]{3}.[[:upper:]].{3}[[:upper:]].{3}[[:upper:]].{3}[[:upper:]].{4}[[:upper:]].{2}[[:upper:]].{3}[[:upper:]].{4}$Uppercase at positions 0,1,2,4,8,12,16,21,24,28
5(?:.*\x5f.*)Contains at least one _ (0x5f)
6(?:.[^0-9]*\d.*){5}Minimum 5 digits
7.{24}\x54.\x65.\x54.*Position 24=T, 26=e (0x65), 28=T
8^.{4}[X-Z]\d._[A]\D\d.................[[:upper:]][n-x]{2}[n|c].$Constraints on positions 4-10 and 28-32
9.{11}_T[h|7]\d_[[:upper:]]\dn[a-h]_[O]\d_[[:alpha:]]{3}_.{5}Constraints on positions 11-27

Stage 2: Position Constraint Mapping

Combining all 9 regex rules, each position (0-32) gets a set of constraints:

Pos  Char  Source
---  ----  ------
 0   H     Rule 2 (hex 0x48)
 1   T     Rule 2 (hex 0x54)
 2   B     Rule 2 (hex 0x42)
 3   {     Rule 3 (hex 0x7b)
 4   Y     Rule 8 [X-Z] + Rule 4 uppercase
 5   0     Rule 8 \d
 6   u     Rule 8 any char
 7   _     Rule 5 + Rule 8 separator
 8   A     Rule 8 [A] + Rule 4 uppercase
 9   r     Rule 8 \D (non-digit)
10   3     Rule 8 \d
11   _     Rule 9 separator
12   T     Rule 9 T + Rule 4 uppercase
13   h     Rule 9 [h|7]
14   3     Rule 9 \d
15   _     Rule 9 separator
16   K     Rule 4 uppercase + Rule 9 [[:upper:]]
17   1     Rule 9 \d
18   n     Rule 9 n
19   g     Rule 9 [a-h]
20   _     Rule 9 separator
21   O     Rule 9 [O] + Rule 4 uppercase
22   ?     Rule 9 \d → digit, but WHICH one?
23   _     Rule 9 separator
24   T     Rule 7 (hex 0x54) + Rule 4 uppercase
25   h     Rule 9 [[:alpha:]]
26   e     Rule 7 (hex 0x65)
27   _     separator
28   T     Rule 7 + Rule 8 [[:upper:]]
29   o     Rule 8 [n-x]
30   w     Rule 8 [n-x]
31   n     Rule 8 [n|c]
32   }     Rule 3 (hex 0x7d)

Regex constraints give us: HTB{REDACTED?_The_Town} — position 22 remains undetermined (any digit 0-9).

Stage 3: ASCII Code Product Verification (check_input)

Reverse engineering the check_input function revealed additional validation. The binary extracts 7 substrings and computes the product of ASCII codes for each character (via multiply_characters, using u128 arithmetic), comparing the result with a hardcoded constant:

RangeSubstringExpected Product
[4..7)Y0u0x7a070 (499824)
[8..11)Ar30x5c436 (377910)
[12..15)Th30x6cc60 (445536)
[16..20)K1ng0x27b5776 (41637750)
[21..23)O?0x10f9 (4345)
[24..27)The0xd76a0 (882336)
[28..32)Town0x7465a58 (122051160)

Key calculation for position 22:

  • Substring [21..23) = "O?" must yield product 4345
  • ord('O') = 79
  • 4345 / 79 = 55 = ord('7')
  • Therefore, position 22 = 7

Solution

#!/usr/bin/env python3
"""
Rega's Town — HackTheBox Reverse Engineering
Recovering the flag from regex constraints + ASCII product check
"""

# 9 regex patterns extracted from the binary via strings
regexes = [
    r'^.{33}$',                          # length 33
    r'(?:^[\x48][\x54][\x42]).*',        # starts with HTB
    r'^.{3}(\x7b).*(\x7d)$',             # pos3={, ends with }
    r'^[[:upper:]]{3}.[[:upper:]].{3}[[:upper:]].{3}[[:upper:]].{3}[[:upper:]].{4}[[:upper:]].{2}[[:upper:]].{3}[[:upper:]].{4}$',
    r'(?:.*\x5f.*)',                      # contains _
    r'(?:.[^0-9]*\d.*){5}',              # minimum 5 digits
    r'.{24}\x54.\x65.\x54.*',            # pos24=T, pos26=e, pos28=T
    r'^.{4}[X-Z]\d._[A]\D\d.................[[:upper:]][n-x]{2}[n|c].$',
    r'.{11}_T[h|7]\d_[[:upper:]]\dn[a-h]_[O]\d_[[:alpha:]]{3}_.{5}',
]

# From regex constraints: HTB{REDACTED?_The_Town}
# Position 22 is unknown — determine via ASCII product check

# Hardcoded product for substring [21..23) = "O?"
expected_product = 0x10f9  # 4345
o_ascii = ord('O')         # 79
missing_char = expected_product // o_ascii  # 4345 / 79 = 55
assert expected_product == o_ascii * missing_char
print(f"Position 22 = chr({missing_char}) = '{chr(missing_char)}'")  # '7'

flag = "HTB{REDACTED}"
print(f"Flag: {flag}")

# Verification of all product checks
substrings = {
    (4, 7):   0x7a070,    # Y0u
    (8, 11):  0x5c436,    # Ar3
    (12, 15): 0x6cc60,    # Th3
    (16, 20): 0x27b5776,  # K1ng
    (21, 23): 0x10f9,     # O7
    (24, 27): 0xd76a0,    # The
    (28, 32): 0x7465a58,  # Town
}

for (start, end), expected in substrings.items():
    substr = flag[start:end]
    product = 1
    for c in substr:
        product *= ord(c)
    assert product == expected, f"FAIL: {substr} product={product} expected={expected}"
    print(f"  [{start}..{end}) = '{substr}' → product = {product} ✓")

print(f"\nAll checks passed! Flag: {flag}")
</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR