| name | screenshot-burp |
| description | Capture a Burp Suite Repeater request/response as a PoC image (targets/<eng>/poc/) by driving the Burp MCP + the Kali GUI. Replays a request in a Repeater tab, sends it, and grabs the request+response panes - a Burp-native PoC (client report / CTF writeup). Use when you want the evidence to come from Burp rather than a curl/terminal card, or whenever you drive a target through Burp and need the images. Pairs with hunt-burp. |
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]
scripts/capture.sh burp thm_x flag1 10.1.1.1 5000 true POST /login /tmp/login_body.txt "ECorp login"
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
xdotool MOUSE 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 BApp MCP tab) needs a human mouse action.
- Window offset:
getwindowgeometry -> the client area sits at screen (0, ~35); the import -window
grab 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 -o dir: the
sudo-as-seat-user import can't write into /tmp/poc if 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_state all run fine across many back-to-back
per-call sessions. capture.sh burp never calls send_http1_request (it Sends in the GUI via Ctrl+Space,
human-equivalent, which bypasses the approval gate), so it is unaffected. If create_repeater_tab itself
fails, the server is down/unreachable -> check scripts/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
getmouselocation over Burp reports window:0 and 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.py already did this;
capture.sh burp now does too.)
- Interactivity precheck = mouse
getmouselocation over Burp returns the Burp WID (not window:0). This is
the RELIABLE check; wmctrl -lG is 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 read
get_active_editor_contents and stop when it shows the created request's METHOD PATH line (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+Space sends the now-confirmed tab; import -window $WID grabs it. The run prints
GRAB_OK ... (verified tab: <marker>); a GRAB_FAIL tells you why (locked seat the unlock did not clear, or
MCP down -> burp-transport.sh).
CAPTURE was never the problem: import -window works headless; flameshot FAILS on this seat ("Unable to
capture screen" -- no DBus/portal in the minimal X), so for a tighter crop use import -window $WID -crop WxH+X+Y +repage or maim/scrot -a (pure X11), never flameshot here.
Manual fallback (what the script automates)
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}"'
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"'
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).