Lucky Dice HTB Challenge Write-Up




At first glance, Lucky Dice looks straightforward: watch players roll dice, figure out who won each round, and type the answer. Simple enough - until you notice the 0.3 second timeout and 100 rounds requirement. No human can reliably respond that fast, 100 times in a row. The challenge is telling you to write a bot.

Game Rules

1 100 rounds must be completed
2 8 to 13 players per round (randomized)
3 Dice grow each round: dice_nr = rnd × 2 + 2
4 Each player's dice are summed → their score
5 Highest total wins the round
⚡ Tiebreaker: the last player (by roll order) with the highest score wins
6 0.3 seconds to submit your answer

The Timeout Check

Python
timeout = 0.3
start = time.time()
answer = input('> ')
if time.time() - start > timeout:
    print("Mate... your are too slow! It seems your CPU is too old!")
    return False
if answer != result:
    print('Hey! I think your scoring is off... Check your RAM... It may be corrupted!')
    return False

The Critical Edge Case: Tiebreaker

WRONG

winner = max(player_scores, key=lambda p: player_scores[p])

Returns the first player with max score — fails on ties!

CORRECT

winner = None
for player_num, score in players_ordered:
    if score == max_score:
        winner = player_num  # overwrites → last match wins

Stores players in order and overwrites on ties → last player wins!

Full Solver Script

Python 3
#!/usr/bin/env python3
import socket
import re

HOST = "154.57.164.82"
PORT = 32011

def recv_until_prompt(s):
    data = b""
    while True:
        try:
            chunk = s.recv(4096)
            if not chunk:
                break
            data += chunk
            if data.endswith(b"> "):
                break
        except socket.timeout:
            break
    return data.decode("utf-8", errors="replace")

def solve():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    s.settimeout(10)

    intro = recv_until_prompt(s)
    print(intro)
    s.sendall(b"1\n")

    for rnd in range(100):
        output = recv_until_prompt(s)
        print(output)

        lines = output.split("\n")
        players_ordered = []

        for line in lines:
            m = re.match(r"Player\s+(\d+):\s+([\d\s]+)", line.strip())
            if m:
                player_num = int(m.group(1))
                dice = list(map(int, m.group(2).strip().split()))
                players_ordered.append((player_num, sum(dice)))

        if not players_ordered:
            print("[!] Could not parse player scores!")
            break

        max_score = max(score for _, score in players_ordered)
        winner = None
        for player_num, score in players_ordered:
            if score == max_score:
                winner = player_num

        print(f"  --> Round {rnd+1}: Winner = Player {winner} (score={max_score})")
        s.sendall(f"{winner}\n".encode())

    final = b""
    try:
        while True:
            chunk = s.recv(4096)
            if not chunk:
                break
            final += chunk
    except:
        pass

    print("\n=== FINAL OUTPUT ===")
    print(final.decode("utf-8", errors="replace"))
    s.close()

if __name__ == "__main__":
    solve()

Running the Solver

kali@htb
$ python3 lucky_dice_solver.py
=== Round 100 ===
Player 1: 4 2 6 ...
...
Who wins this round?
>
--> Round 100: Winner = Player 5 (score=742)
=== FINAL OUTPUT ===
Yes.. Correct!
Nice job!
Here is your prize:
HTB{xxxxxxxx-xxxxxx-xxxxxxxx}
Kebal Bhandari

As an experienced Fullstack Senior Software Developer with a strong background in IT administration and a growing interest in cybersecurity, I am eager to learn more about the complexities of online security, risk management, and data analytics.

Post a Comment

Express your opinion

Previous Post Next Post

Download Cyber Master

Download Cyber Master