Back to writeups
HTBcodingeasysolved

PINsmith

2 Jul 2026 · by 0xIDA

Solvers

PINsmith

Author: 0xIDA
Platform: HTB · Category: coding · Difficulty: easy

Solvers

Summary

A coding challenge where we must generate all possible PIN combinations matching a known partial pattern, respecting a "no adjacent repeats" policy. The pattern contains known digits (0-9) and wildcards (*). The solution uses backtracking to enumerate all valid PINs in lexicographical order.

Solution

Step 1: Understand the problem

The challenge presents a scenario where a CygnusCorp system is locked behind a numeric PIN. Some digits of the PIN are known, others are unknown (*). The security policy states that no two adjacent digits can be the same. The PIN length is between 2 and 10 digits.

Input format: A single string with known digits and * for unknown positions.
Output format: All valid PINs, one per line, sorted ascending lexicographically.

Step 2: Solve with backtracking

The approach uses depth-first search with backtracking:

For each position in the pattern:
  - If the digit is known (not *): place it only if it differs from the previous digit
  - If the digit is unknown (*): try each digit 0-9 that differs from the previous digit
  - When all positions are filled, add the PIN to results

The lexicographic order is automatically satisfied by trying digits from '0' to '9'.

Step 3: Submit the solution

The challenge runs on a coding platform with a Monaco editor and a /run API endpoint. Submitting the Python solution passes all hidden test cases and returns the flag.

Python solution:

import sys

def solve():
    pattern = sys.stdin.readline().strip()
    n = len(pattern)
    res = []
    
    def backtrack(pos, cur):
        if pos == n:
            res.append(''.join(cur))
            return
        if pattern[pos] != '*':
            d = pattern[pos]
            if not cur or cur[-1] != d:
                cur.append(d)
                backtrack(pos + 1, cur)
                cur.pop()
        else:
            for d in '0123456789':
                if not cur or cur[-1] != d:
                    cur.append(d)
                    backtrack(pos + 1, cur)
                    cur.pop()
    
    backtrack(0, [])
    sys.stdout.write('\n'.join(res))

if __name__ == '__main__':
    solve()

Verification example:

PatternValid PINs CountSamples
1*38103, 123, 143, 153, 163, 173, 183, 193
0*09010, 020, 030, 040, 050, 060, 070, 080, 090
****7,2900101, 0102, ..., 9897
12**811201, 1202, ..., 1298

Step 4: Receive the flag

After submitting the code via /run API, all test cases pass and the flag is returned.

Flag

HTB{3ff1c13nt_P1n_Cr4cK1nG}

Remediation (real-world takeaway)

  • No adjacent repeats is an extremely weak constraint — for a 4-digit PIN with 2 wildcards, there are still 81 possible values. For a fully unknown 4-digit PIN, 7,290 values remain.
  • PIN-based authentication should use rate limiting, account lockout, and MFA to prevent brute-force attacks.
  • Leaking even partial PIN digits dramatically reduces the search space — store only hashed credentials.
  • For systems where educated brute-forcing is a concern, enforce cryptographically random secrets with sufficient entropy.