Screenshot: Burp Repeater request/response PoC
Turn a Burp Repeater exchange into a report-ready request + response image. This is the Burp-native
counterpart to Skill(screenshot) (curl/terminal cards): when you drive a target through Burp, capture
the proof FROM Burp. Prereqs are the same as Skill(hunt-burp) (Burp running + the MCP Server BApp, SSE
on 127.0.0.1:9876; verify with bash /root/vm.sh 'python3 ~/burp-mcp-cli.py list').
One command (use this)
scripts/capture.sh burp <eng> <slug> <host> <port> <https:true|false> <method> <path> [bodyfile] [tabname]
# POST with a body file (forged/complex bodies -> write to a file, avoids shell quoting):
scripts/capture.sh burp thm_x flag1 10.1.1.1 5000 true POST /login /tmp/login_body.txt "ECorp login"
# simple GET:
scripts/capture.sh burp thm_x flag3 10.1.1.1 3000 false GET /challenge/solve
It: (1) create_repeater_tab via the MCP with the raw request, (2) activates Burp on the seat display,
focuses the request editor, sends with Ctrl+Space (Burp's Repeater Send hotkey), (3) import-grabs
the window and pulls targets/<eng>/poc/NN-<slug>.png, printing the ![]() ref. Drop that ref into
walkthrough.md so the image actually renders in Obsidian (an un-referenced PNG in poc/ is invisible
in the notes - only reachable by opening the folder).
Crypto-forged / signed requests: give the exploit script a --curl-style mode that writes the exact
body to a file (e.g. /tmp/login_body.txt), then pass it as bodyfile. The Repeater tab then holds the
real forged request, so the PoC is Burp-native and reproducible.
Gotchas baked into capture.sh burp (the burp mode) (why hand-rolling this failed the first time)
- Grab as the SEAT user, not root. Burp may be root-owned but it DRAWS on the desktop user's X
session (the desktop login on
:0).who-> the line with a(:N)display gives the user + display; use their~/.Xauthority. A root-over-SSH grab has no X display. - Send = Ctrl+Space (KEYBOARD only); mouse is dead. Java Swing IGNORES synthetic
xdotoolMOUSE clicks (button/tab/pixel clicks are silent no-ops), but KEYBOARD events land once the window is activated (windowactivate --sync):Ctrl+Shift+R(focus Repeater),Ctrl+=(next sub-tab),Ctrl+Space(Send). Drive everything by keyboard; anything with no hotkey (e.g. the BAppMCPtab) needs a human mouse action. - Window offset:
getwindowgeometry-> the client area sits at screen (0, ~35); theimport -windowgrab starts at the client top, so screen_y = image_y + 35 (only matters if you ever DO need a click on a WM that accepts synthetic clicks; this one does not). - Write the grab to a WORLD-WRITABLE path (
/tmp/capture_burp_*.png), never a root-owned-odir: the sudo-as-seat-userimportcan't write into/tmp/pocif root created it (silent EACCES = "no PNG"). - The "SSE wedge" was a MISDIAGNOSIS (corrected 2026-07-24). The only MCP call that ever hung is
send_http1_request, and that is the extension's target-approval gate (a non-approved target raises a GUI approval prompt a headless seat cannot answer -> 15s timeout), NOT a per-session wedge.create_repeater_tab,get_active_editor_contents,url_encode,set_proxy_intercept_stateall run fine across many back-to-back per-call sessions.capture.sh burpnever callssend_http1_request(it Sends in the GUI viaCtrl+Space, human-equivalent, which bypasses the approval gate), so it is unaffected. Ifcreate_repeater_tabitself fails, the server is down/unreachable -> checkscripts/burp/burp-transport.sh(see [[burp-mcp]]).
Selecting the finding's tab (SOLVED 2026-07-24, Burp 2026.3.x, verified end-to-end)
create_repeater_tab appends the tab RIGHTMOST but does NOT focus it, so a naive grab caught whatever tab was
last active (the old stale-tab PoCs). capture.sh burp now SELECTS the intended tab deterministically and
VERIFIES it before Send/grab, so a wrong-tab PoC is impossible. The sequence (all baked into the burp mode):
- Unlock + wake the seat FIRST. A Kali screen LOCK (seat0) routes synthetic input to the locker, so
getmouselocationover Burp reportswindow:0and NO key/click lands -- burpshot then silently caught the wrong tab.loginctl unlock-session <seat0-sid>(root) dismisses the lock;xset dpms force on+xset s off(seat user) wake the display. Without this a locked/idle VM fails the precheck. (shot.pyalready did this;capture.sh burpnow does too.) - Interactivity precheck = mouse
getmouselocationover Burp returns the Burp WID (notwindow:0). This is the RELIABLE check;wmctrl -lGis NOT -- it reports "no managed windows" on this no-WM seat even when input lands, a false negative. - SELECT by keyboard + oracle.
Ctrl+=(go_to_next_tab, it WRAPS) steps sub-tabs; after each step readget_active_editor_contentsand stop when it shows the created request'sMETHOD PATHline (cap 16, fail loud if never confirmed). The old "Ctrl+= does not move the tab" finding was from the LOCKED-seat era when no input landed at all -- once unlocked,Ctrl+=selects the tab AND focuses its editor, which the oracle reads. (Marker = the request line; a distinctive path keeps it unambiguous -- identical request-lines across tabs match the first found.) - Send + grab.
Ctrl+Spacesends the now-confirmed tab;import -window $WIDgrabs it. The run printsGRAB_OK ... (verified tab: <marker>); aGRAB_FAILtells you why (locked seat the unlock did not clear, or MCP down ->burp-transport.sh). CAPTURE was never the problem:import -windowworks headless; flameshot FAILS on this seat ("Unable to capture screen" -- no DBus/portal in the minimal X), so for a tighter crop useimport -window $WID -crop WxH+X+Y +repageormaim/scrot -a(pure X11), never flameshot here.
Manual fallback (what the script automates)
# 1) stage the request as a Repeater tab (root, via MCP)
bash /root/vm.sh 'python3 ~/burp-mcp-cli.py call create_repeater_tab "{\"content\":\"GET /x HTTP/1.1\r\nHost: T:80\r\nConnection: close\r\n\r\n\",\"targetHostname\":\"T\",\"targetPort\":80,\"usesHttps\":false}"'
# 2) send + grab as the seat user (detect the desktop user + display from `who`)
bash /root/vm.sh 'U=$(who | awk "/\(:[0-9]/{print \$1;exit}"); D=$(who|grep -oE "\(:[0-9]+"|head -1|tr -d "(")
sudo -u "$U" env DISPLAY="$D" XAUTHORITY=/home/$U/.Xauthority bash -c "
WID=\$(xdotool search --name \"Burp Suite Professional\" | head -1)
xdotool windowactivate --sync \$WID; xdotool mousemove 500 400 click 1; sleep .4
xdotool key ctrl+space; sleep 4; import -window \$WID /tmp/burp.png"'
# 3) pull it
bash /root/vm.sh 'base64 -w0 /tmp/burp.png' | base64 -d > targets/<eng>/poc/NN-slug.png
Redaction / boundary
Same as Skill(screenshot): images live only under targets/<eng>/ (gitignored); run Skill(evidence)
before a client report (Burp responses can carry cookies/PII). Never embed in wiki/.
Output
Report: the poc/NN-slug.png saved + the ![]() ref added to walkthrough.md; note if the MCP wedged
(and whether you restarted it or fell back to the proxy).