Skip to content

SECURE_CONNECTION//PRESS[CTRL+J]FOR ROOT ACCESS

BACK TO INTEL
MiscEasy

Stop Drop And Roll

CTF writeup for Stop Drop And Roll from HTB CTF TRY OUT

//Stop Drop and Roll

Challenge: Stop Drop and Roll

Remote: nc 94.237.57.115 47985

Flag format: HTB{...}


>Summary

This challenge is an interactive network service that implements a simple mapping game. The server presents a short tutorial and then repeatedly sends challenges: a comma-separated sequence of scenario words drawn from {GORGE, PHREAK, FIRE}. The correct reply is a dash-separated sequence mapping each scenario to a corresponding action:

  • GORGE -> STOP

  • PHREAK -> DROP

  • FIRE -> ROLL

After successfully answering a series of challenges the server returns the flag.

I automated the interaction with a short Python script 001_solve.py that connects to the remote host, answers the ready prompt, parses each challenge, sends the correct response, and prints the flag when seen.


>Recon and Analysis

  1. I first inspected the workspace. There were no local challenge binaries or scripts to analyze; the challenge is remote-only.

  2. I connected with netcat to the remote host to observe behavior and the tutorial text. The server clearly described the mapping and the format for multi-item responses (comma-separated input, dash-separated output).

  3. The protocol is simple plain-text over TCP; no authentication or exotic encoding. Automating is straightforward and reliable.

Edge cases to consider

  • The tutorial includes the scenario words for demonstration; the solver must avoid replying to those tutorial lines.

  • The server asks a readiness confirmation Are you ready? (y/n) that must be answered with y to start.

  • Challenges might be single words or multiple words; responses must preserve order and be connected by -.

  • Ensure we detect the flag anywhere in the server output (it uses format HTB{...}).


>Solution approach

Write a short, robust Python client that:

  1. Connects to 94.237.57.115:47985 with a socket.

  2. Reads incoming lines and prints them for logging.

  3. When the server asks Are you ready? (y/n), send y.

  4. Only after sending y, parse challenge lines for the tokens GORGE, PHREAK, FIRE.

  5. Build the response by mapping tokens to their actions and joining with -.

  6. Send responses with a newline and keep listening until a flag HTB{...} appears.

This approach is resilient to the tutorial text and simple to implement.


>Code: 001_solve.py

Below is the full solver script used. It is intentionally verbose for visibility (prints server messages, parsed sequences, and outgoing responses).

python

#!/usr/bin/env python3

"""

001_solve.py

Automated solver for 'Stop Drop and Roll' (HTB MISC).

  

Connects to the remote service, parses scenario sequences like

"GORGE, FIRE, PHREAK" and replies with the mapped actions

"STOP-ROLL-DROP". Prints the HTB{...} flag when seen.

  

Usage: python3 001_solve.py

"""

  

import socket

import re

import time

import sys

  

HOST = '94.237.57.115'

PORT = 47985

  

MAPPING = {

    'GORGE': 'STOP',

    'PHREAK': 'DROP',

    'FIRE': 'ROLL',

}

  

WORD_RE = re.compile(r'GORGE|PHREAK|FIRE')

FLAG_RE = re.compile(r'HTB\{.*?\}')

  
  

def recv_all(sock, timeout=2.0):

    """Receive available data (non-blocking-ish) and return decoded text."""

    sock.settimeout(timeout)

    data = b''

    try:

        while True:

            part = sock.recv(4096)

            if not part:

                break

            data += part

            if len(part) < 4096:

                # no more immediate data

                break

    except socket.timeout:

        pass

    except Exception:

        pass

    try:

        return data.decode(errors='ignore')

    except Exception:

        return ''

  
  

def solve_loop(host, port):

    print('\n=== 🕹️  Stop Drop and Roll solver starting ===')

    print(f'Connecting to {host}:{port}...')

    with socket.create_connection((host, port), timeout=10) as s:

        s.settimeout(10)

        buffer = ''

        started = False

        while True:

            data = recv_all(s, timeout=2.0)

            if not data:

                # nothing new, keep waiting

                time.sleep(0.1)

                continue

            buffer += data

            for line in data.splitlines():

                line = line.strip()

                if not line:

                    continue

                print('\n📥 Server:', line)

  

                # Check for flag anywhere in the line

                mflag = FLAG_RE.search(line)

                if mflag:

                    print('\n🎯 FLAG found:', mflag.group(0))

                    print('=== ✅ Done ===\n')

                    return

  

                # If the server asks if we're ready, answer 'y' (robust substring check)

                low = line.lower()

                if 'ready' in low and '(y/n)' in low:

                    try:

                        print('➡️  Sending: y')

                        s.sendall(b'y\n')

                        started = True

                        print('🏁 Game started — now listening for challenges')

                        continue

                    except BrokenPipeError:

                        print('⚠️  Connection closed by remote')

                        return

  

                # If the game hasn't started (we're in tutorial), don't reply to

                # scenario words. Only respond after we've answered 'y'.

                if not started:

                    continue

  

                # Now we are in the game: respond to scenario lines. Only reply

                # when the line looks like an actual challenge (comma-separated

                # or multiple words).

                seq = WORD_RE.findall(line)

                if seq and (',' in line or len(seq) > 1 or line.isupper()):

                    resp = '-'.join(MAPPING.get(w, 'UNK') for w in seq)

                    print('🔎 Parsed sequence:', seq)

                    print('➡️  Sending response:', resp)

                    try:

                        s.sendall((resp + '\n').encode())

                    except BrokenPipeError:

                        print('⚠️  Connection closed by remote')

                        return

  
  

if __name__ == '__main__':

    try:

        solve_loop(HOST, PORT)

    except KeyboardInterrupt:

        print('\nInterrupted by user')

        sys.exit(1)

    except Exception as e:

        print('Error:', e)

        sys.exit(2)

  

>Sample run (trimmed)

Below is an excerpt from the script running against the remote service (output is verbatim except for trimming):

📥 Server: What do you do? 📥 Server: PHREAK, FIRE, FIRE, GORGE 🔎 Parsed sequence: ['PHREAK', 'FIRE', 'FIRE', 'GORGE'] ➡️  Sending response: DROP-ROLL-ROLL-STOP ... [many rounds omitted for brevity] ... 📥 Server: Fantastic work! The flag is HTB{1_wiLl_sT0p_dR0p_4nD_r0Ll_mY_w4Y_oUt!} 🎯 FLAG found: HTB{1_wiLl_sT0p_dR0p_4nD_r0Ll_mY_w4Y_oUt!} === ✅ Done ===

>Final flag

HTB{1_wiLl_sT0p_dR0p_4nD_r0Ll_mY_w4Y_oUt!}


>Notes & next steps

  • If you want the script to log every interaction to a numbered file 003_session_log.txt, I can add that.

  • If you'd like the run wrapped in a Python virtualenv and a small README.md with usage and requirements, I can add that too.

  • The current script is synchronous and simple; for large-scale automation (multiple concurrent sessions) a non-blocking or threaded approach would be better.