← Back to Writeups
HTBMediumML

dualflow

D3v0o0Nu119/2/20263 min read
#ml#htb#medium#coordinate_perturbation#likelihood_margin_optimization#white_box_adversarial_example

dualflow

Platform: Umdctf | Category: ML | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-04-25 | Status: Solved Techniques: coordinate_perturbation, likelihood_margin_optimization, white_box_adversarial_example

Summary

Task: submit a float32 window close to a provided reference so it passes three RealNVP-based acceptance checks. Solution: use a white-box adversarial perturbation, changing one coordinate of the reference by +0.03 to push the flow_1 likelihood and margin far above the required thresholds while staying inside the L-infinity budget.

Recon

Port scan

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

Enumeration highlights

  • Event: umdctf | ID: 20260425_umdctf_dualflow
  • Tags: float32, realnvp, normalizing_flow, adversarial_example, white_box
  • Indicators: two flow log-probabilities are compared as a classifier, submission is constrained only by a small L-infinity budget, acceptance depends on likelihood margin and Jacobian band checks, reference sample is provided locally as a numpy array
  • Source: 20260425_umdctf_dualflow.md

Foothold

Vulnerability / Misconfiguration

  1. coordinate_perturbation
  2. likelihood_margin_optimization
  3. white_box_adversarial_example
bash
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

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

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • coordinate_perturbation
  • likelihood_margin_optimization
  • white_box_adversarial_example
  • Tags: float32, realnvp, normalizing_flow, adversarial_example, white_box

Original Writeup

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

Description

submit base64(numpy float32 array, shape (5, 64)):

The service loads a reference window and checks whether our submitted float32 array stays within EPS = 0.08 in L-infinity distance. It then evaluates the sample under two RealNVP flows and only prints the flag if the sample looks realistic to flow_1 and strongly prefers class 1 over class 0.

Analysis

challenge.py exposes the full decision rule:

  • shape must be (5, 64)
  • values are compared to reference_window.npy
  • linf <= 0.08
  • margin = log q1 - log q0 >= 30
  • log q1 >= 932.8031
  • log_det1 must lie in [1367.1451, 1595.0465]

The important point is that this is a white-box setting. We have the reference input, the model code, and both flow checkpoints. The reference sample itself is not close to the target class boundary in the right direction: its margin is about -1.90, so we must meaningfully increase log q1 - log q0 while keeping the perturbation tiny.

In practice, no numerical trick was needed. A simple coordinate search was enough: flatten the reference array and add +0.03 at index 205, which is element [3, 13] in the original (5, 64) layout.

That single change already satisfies every condition:

  • linf = 0.03
  • margin = 105.70
  • log_q1 = 986.23
  • log_det1 = 1526.48

So the challenge is essentially a straightforward adversarial-example task against a flow-based discriminator.

Solution

Load the reference window, perturb one coordinate, save the result as a NumPy array, then base64-encode the .npy payload for submission.

python
#!/usr/bin/env python3
import base64
import io
import numpy as np

ref = np.load("reference_window.npy").astype(np.float32)
sub = ref.copy().reshape(-1)
sub[205] += np.float32(0.03)   # same as ref[3, 13] += 0.03
sub = sub.reshape(5, 64).astype(np.float32)

buf = io.BytesIO()
np.save(buf, sub)
print(base64.b64encode(buf.getvalue()).decode())

Submitting that array to the remote service returns the success line and the flag.

</details>

signed by XESXOR