← Back to Writeups
HTBN/AMisc

WTF_ELECTRICALENGINEERING

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

WTF_ELECTRICALENGINEERING

Platform: Broncoctf2026 | Category: Misc | Type: Challenge | Difficulty: Hard | OS: NA | Author: D3v0o0Nu11 | Date: 2026-07-11 | Status: Solved Techniques: binary_group_to_ascii_decoding, msb_bit_plane_extraction, multi_stage_oob_link_following, radix4_booth_pp_decoder_evaluation, url_extraction_from_stego

Summary

Task: two academic Booth-multiplier paper figures (PNG) hide a multi-stage puzzle; the paper identity is misdirection. Solution: extract URLs from bit-plane 7 (MSB) of the red channel, follow tinyurl -> Google Drive to a .b input sequence, and since inputs are only 0000/1110 the radix-4 Booth PP decoder collapses to 1110->1 / 0000->0, giving 18 ASCII bytes = the flag.

Recon

Port scan

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

Enumeration highlights

  • Event: broncoctf2026 | ID: 20260711_broncoctf2026_wtf_electricalengineering
  • Tags: multi_stage, ascii_decoding, misdirection, verilog, png_steganography, red_channel, bit_plane_stego, msb_stego, radix4_booth, booth_encoder_decoder, tinyurl, google_drive
  • Indicators: academic IEEE/VLSI paper figures given as challenge images, normal LSB/alpha/binwalk/strings/exiftool all find nothing, hidden data lives in bit-plane 7 (MSB) of a single channel, URLs (tinyurl) extracted from stego lead to Google Drive folders, a .b binary-formatted input file plus Verilog hints imply simulating a described logic circuit
  • Source: 20260711_broncoctf2026_wtf_electricalengineering.md

Foothold

Vulnerability / Misconfiguration

  1. Binary_group_to_ascii_decoding
  2. Msb_bit_plane_extraction
  3. Multi_stage_oob_link_following
  4. Radix4_booth_pp_decoder_evaluation
  5. Url_extraction_from_stego
<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

  • binary_group_to_ascii_decoding
  • msb_bit_plane_extraction
  • multi_stage_oob_link_following
  • radix4_booth_pp_decoder_evaluation
  • url_extraction_from_stego
  • Tags: multi_stage, ascii_decoding, misdirection, verilog, png_steganography, red_channel, bit_plane_stego, msb_stego, radix4_booth, booth_encoder_decoder, tinyurl, google_drive

Original Writeup

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

Description

I'm supposed to find the flag somewhere but this guy just sent me two images to try to find it! What the flip, I don't know anything about Electrical Engineering!!

Two files are provided:

  • ChallengeCircuit.png (301x250 RGBA) — a CMOS transistor-level schematic of a radix-4 Booth partial-product decoder.
  • Challenge.png (715x396 RGBA) — "TABLE VI — Comparisons of The Radix-4 Booth Designs for Generating One Partial Product Row".

Goal: recover the bronco{...} flag hidden somewhere in/behind these images.

Analysis

Recon — the paper is a red herring

Reverse-image searching both figures identifies their common source:

Yen-Jen Chang, Yu-Cheng Cheng, Shao-Chi Liao, Chun-Huo Hsiao, "A Low Power Radix-4 Booth Multiplier With Pre-Encoded Mechanism," IEEE Access vol. 8, pp. 114842–114853, 2020, DOI 10.1109/ACCESS.2020.3003684.

  • ChallengeCircuit.png = Figure 9(b), the proposed low-cost decoder.
  • Challenge.png = Table VI.

Lesson (misdirection): identifying the paper is NOT the solution. Guessing the normalized paper title as the flag (e.g. bronco{a_low_power_radix-4_booth_multiplier_with_pre-encoded_mechanism}) is wrong. The paper is only context — it teaches the Booth decoder needed in the final stage.

Failed approaches (do not repeat)

  • PNG chunk inspection — no tEXt/zTXt/trailing data.
  • Alpha channel — all 255.
  • Standard LSB (bit 0) extraction on R/G/B/A — nothing.
  • binwalk, strings, exiftool — nothing.
  • Table numeric values (transistor counts, delays, power) do NOT decode to ASCII.
  • The circuit's small truth table alone is not the payload.

Breakthrough — bit-plane 7 (MSB) of the RED channel

The hidden data is in bit-plane 7 (the most significant bit) of the red channel, read row-major (top-left → bottom-right), packed 8 bits per byte, MSB-first. The key insight is to check HIGH bit-planes and single-channel extraction, not just LSB.

Extraction yields a printable URL in each image:

  • ChallengeCircuit.pnghttps://tinyurl.com/3pya79we
  • Challenge.pnghttps://tinyurl.com/hnexnehb

Solution

Stage 1 — MSB bit-plane extraction

#!/usr/bin/env python3
# Extract bit-plane 7 (MSB) of the RED channel, row-major, MSB-first packing.
from PIL import Image
import numpy as np

def extract_msb_red(path):
    img = np.array(Image.open(path).convert("RGBA"))
    red = img[:, :, 0].flatten()          # row-major
    bits = (red >> 7) & 1                  # bit-plane 7 (MSB)
    n = (len(bits) // 8) * 8
    bytes_out = np.packbits(bits[:n])      # MSB-first by default
    # keep the leading printable ASCII run
    s = bytes(bytes_out).split(b"\x00")[0]
    printable = bytes(c for c in s if 32 <= c < 127)
    return printable.decode(errors="ignore")

print(extract_msb_red("ChallengeCircuit.png"))  # https://tinyurl.com/3pya79we
print(extract_msb_red("Challenge.png"))          # https://tinyurl.com/hnexnehb

Stage 2 — follow the links (OOB)

  • tinyurl.com/3pya79we → Google Drive folder "BroncoCTFChallengeCircuit" containing hintscircuit.txt.
  • tinyurl.com/hnexnehb → Google Drive folder "BroncoCtfChallengeNonCircuit" containing hintstable.txt and inputsequence.b.

Files download via https://drive.google.com/uc?export=download&id=FILE_ID.

hintscircuit.txt (circuit folder):

Here the link to where you can find the actual gate level diagram (ResearchGate publication 342326148, page 6). Use readmemb instead of writing out all the binary yourself. On the gate-level diagram you don't need to worry about zero_i as it will be zero whatever you do. Use the same method (MSB stego) to grab the input sequence. Once you feed the input binary to the circuit, convert it to ASCII and you get the flag.

hintstable.txt (non-circuit folder):

The binary file is your input sequence. When feeding it into the Verilog, the order should be: MSB = neg_i, then x_j, then nx_{j-1}, LSB = ot_i. zero_i is always zero. Free Verilog: edaplayground; use SystemVerilog/Verilog for testbench + design, Icarus Verilog 12.

Stage 3 — the input sequence

inputsequence.b: 18 rows, each row = 8 space-separated 4-bit groups. Each 4-bit group is {neg_i (MSB), x_j, nx_{j-1}, ot_i (LSB)}. Every group is either 0000 or 1110:

0000 1110 1110 0000 0000 0000 1110 0000
0000 1110 1110 1110 0000 0000 1110 0000
0000 1110 1110 0000 1110 1110 1110 1110
0000 1110 1110 0000 1110 1110 1110 0000
0000 1110 1110 0000 0000 0000 1110 1110
0000 1110 1110 0000 1110 1110 1110 1110
0000 1110 1110 1110 1110 0000 1110 1110
0000 1110 1110 0000 1110 1110 1110 1110
0000 1110 1110 1110 0000 1110 1110 0000
0000 0000 1110 1110 0000 0000 1110 0000
0000 1110 1110 0000 1110 0000 0000 0000
0000 1110 1110 0000 1110 0000 0000 0000
0000 1110 0000 1110 0000 1110 0000 1110
0000 0000 1110 1110 0000 1110 1110 0000
0000 1110 1110 0000 1110 1110 0000 1110
0000 1110 0000 0000 0000 0000 1110 0000
0000 1110 0000 1110 1110 0000 0000 1110
0000 1110 1110 1110 1110 1110 0000 1110

Stage 4 — the elegant shortcut (skip Verilog)

The intended path builds the gate-level radix-4 Booth partial-product (PP) decoder in Verilog (readmemb the .b file, drive the decoder, dump PP bits). But because only two input patterns ever appear, feeding them through the proposed PP decoder gives:

  • PP(0000) = 0
  • PP(1110) = 1

So each 4-bit group collapses to a single output bit. Eight groups per row → one byte → one ASCII character; 18 rows → 18 characters. No simulator required.

#!/usr/bin/env python3
# Radix-4 Booth PP decoder collapses to a 1-bit map on the only two inputs seen.
rows = open("inputsequence.b").read().strip().splitlines()
m = {"1110": "1", "0000": "0"}   # PP(1110)=1, PP(0000)=0
flag = ""
for r in rows:
    bits = "".join(m[g] for g in r.split())   # 8 groups -> 8 bits, MSB-first
    flag += chr(int(bits, 2))                 # 1 byte -> 1 ASCII char
print(flag)   # bronco{REDACTED}

Confirmation: submitted to CTFd /api/v1/challenges/attempt (challenge_id 38) → {"status":"correct"}.

</details>

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

signed by XESXOR