Skip to content

Commit 2ebcf21

Browse files
maxholmanclaude
andcommitted
chore(range): add egress-filtered VMs, reverse-connect target, ssh-bastion pivot, loot app
New scenario VMs: - web-filter (perimeter): exit behind web-only egress, tests WebSocket/443 - ssh-bastion (office): SSH-only egress pivot node - loot (office): app-loot target behind ssh-bastion - udp-only (datacenter): exit behind UDP-53-only egress, tests QUIC on :53 - reverse-target (vault): exit that listens (egress-none), true reverse-connect New layers: app-loot, egress-none, egress-ssh-only, egress-udp53-only, egress-web-only, ssh-bastion Fix wallhack layer: --fixed-role -> --role Port attacker/gateway-perimeter to :443 Add intranet creds.txt loot file Add quickstart recording assets and cross-image workflow Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d6dfd25 commit 2ebcf21

16 files changed

Lines changed: 287 additions & 3 deletions

File tree

.github/workflows/cross-image.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Build Cross Image
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths: [Dockerfile.cross-musl]
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
packages: write
12+
13+
jobs:
14+
build:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v6
18+
19+
- uses: docker/setup-buildx-action@v3
20+
21+
- name: Login to GitHub Container Registry
22+
uses: docker/login-action@v3
23+
with:
24+
registry: ghcr.io
25+
username: ${{ github.actor }}
26+
password: ${{ secrets.GITHUB_TOKEN }}
27+
28+
# Image is PUBLIC on ghcr.io — do NOT add secrets to Dockerfile.cross-musl
29+
- name: Build and push cross Docker image
30+
uses: docker/build-push-action@v6
31+
with:
32+
context: .
33+
file: Dockerfile.cross-musl
34+
tags: ghcr.io/block65/wallhack-cross:x86_64-unknown-linux-musl
35+
push: true
36+
cache-from: type=gha,scope=cross-musl
37+
cache-to: type=gha,mode=max,scope=cross-musl

TODO.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
enable Path MTU Discovery.
2626
- [ ] ICMP as an egress transport — encapsulate the tunnel inside ICMP Echo
2727
packets to bypass firewalls that block all outbound TCP/UDP.
28+
- [ ] **Multiple simultaneous listen addresses**`--listen :4433 --listen :443/tcp`
29+
lets a single daemon accept connections on multiple ports and transports
30+
concurrently. Useful when the exit node is behind a firewall that blocks UDP
31+
but allows 443/TCP: the exit picks whichever it can reach. Implementation:
32+
`ConnectivitySpec::Listen(Vec<AddressSpec>)`, spawn one tokio listener task
33+
per spec, `StatusResponse.listen_addr``repeated string listen_addrs` in
34+
proto. CLI: argh `Vec<String>` for repeated `--listen`. No known tunnel tool
35+
(e.g. ligolo) supports this.
2836
- [ ] HTTP/2 multiplexing
2937
- [ ] Domain fronting support
3038
- [ ] Deterministic TUN addresses based on peer identity

docs/quickstart.tape

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Quickstart demo: help → entry node + exit node connection
2+
# Run with: vhs docs/quickstart.tape
3+
# NOTE: Requires two wallhack instances; use separate IPC socket paths or
4+
# containers if the default /run/user/.../wallhackd.sock conflicts.
5+
6+
Output website/public/quickstart.gif
7+
Output website/public/quickstart.mp4
8+
9+
Set Shell "bash"
10+
Set FontSize 14
11+
Set Width 1400
12+
Set Height 700
13+
Set Theme "Catppuccin Mocha"
14+
Set Padding 8
15+
Set TypingSpeed 40ms
16+
17+
# ── PATH setup (hidden) ─────────────────────────────────────────────────────
18+
Hide
19+
Type `export PATH=./target/release:$PATH`
20+
Enter
21+
Sleep 500ms
22+
Type "clear"
23+
Enter
24+
Sleep 300ms
25+
Show
26+
27+
# ── HELP ─────────────────────────────────────────────────────────────────────
28+
Type "wallhack --help"
29+
Enter
30+
Sleep 5s
31+
32+
# ── TMUX SETUP (hidden) ─────────────────────────────────────────────────────
33+
Hide
34+
Type `tmux kill-session -t demo 2>/dev/null; true`
35+
Enter
36+
Sleep 300ms
37+
38+
Type `tmux new-session -d -s demo -x 200 -y 48`
39+
Enter
40+
Sleep 300ms
41+
42+
# Configure left pane — local / entry node
43+
Type `tmux send-keys -t demo:0.0 'export PATH=./target/release:$PATH && clear' Enter`
44+
Enter
45+
Sleep 500ms
46+
47+
# Split and configure right pane — remote / exit node
48+
Type `tmux split-window -h -t demo:0.0`
49+
Enter
50+
Sleep 300ms
51+
Type `tmux send-keys -t demo:0.1 'export PATH=./target/release:$PATH && clear' Enter`
52+
Enter
53+
Sleep 500ms
54+
55+
# Pane border titles so viewers know which is which
56+
Type `tmux set -t demo pane-border-status top`
57+
Enter
58+
Sleep 200ms
59+
Type `tmux select-pane -t demo:0.0 -T " LOCAL MACHINE "`
60+
Enter
61+
Sleep 200ms
62+
Type `tmux select-pane -t demo:0.1 -T " REMOTE MACHINE "`
63+
Enter
64+
Sleep 200ms
65+
66+
# Focus left pane and attach
67+
Type `tmux select-pane -t demo:0.0`
68+
Enter
69+
Sleep 200ms
70+
Type `tmux attach -t demo`
71+
Enter
72+
Sleep 1s
73+
Show
74+
75+
# ── LOCAL: start entry node on port 888 ─────────────────────────────────────
76+
Type "wallhack entry --listen :888"
77+
Enter
78+
Sleep 4s
79+
80+
# ── REMOTE: connect exit node back to local ─────────────────────────────────
81+
Ctrl+B
82+
Sleep 100ms
83+
Right
84+
Sleep 500ms
85+
86+
Type "wallhack exit --connect 127.0.0.1:888 --name peer1"
87+
Enter
88+
Sleep 5s
89+
90+
# ── LOCAL: see the peer connect ─────────────────────────────────────────────
91+
Ctrl+B
92+
Sleep 100ms
93+
Left
94+
Sleep 3s
95+
96+
# ── QUIT ─────────────────────────────────────────────────────────────────────
97+
Ctrl+C
98+
Sleep 1s
99+
100+
Ctrl+B
101+
Sleep 100ms
102+
Right
103+
Sleep 300ms
104+
Ctrl+C
105+
Sleep 2s
106+

range/layers/app-loot/app/app.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from flask import Flask
2+
app = Flask(__name__)
3+
4+
@app.route("/")
5+
def index():
6+
return """<html><body>
7+
<h2>Internal Loot Server</h2>
8+
<p>flag{FLAG_PLACEHOLDER}</p>
9+
<p>DB credentials: postgres://admin:DB_PASS_PLACEHOLDER@10.99.3.20/prod</p>
10+
</body></html>"""
11+
12+
if __name__ == "__main__":
13+
app.run(host="0.0.0.0", port=5000)

range/layers/app-loot/layer.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
packages:
2+
- python3
3+
- py3-flask
4+
configs:
5+
- app/app.py
6+
start: |
7+
FLAG=$(cat /dev/urandom | tr -dc 'a-f0-9' | head -c 32)
8+
DB_PASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 20)
9+
sed -i "s/FLAG_PLACEHOLDER/$FLAG/" /app/app.py
10+
sed -i "s/DB_PASS_PLACEHOLDER/$DB_PASS/" /app/app.py
11+
python3 /app/app.py &

range/layers/egress-none/layer.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
start: |
2+
iptables -A OUTPUT -p tcp -j DROP
3+
iptables -A OUTPUT -p udp -j DROP
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
start: |
2+
iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
3+
iptables -A OUTPUT -p tcp -j DROP
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
start: |
2+
iptables -A OUTPUT -p tcp -j DROP
3+
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
4+
iptables -A OUTPUT -p udp -j DROP
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
start: |
2+
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
3+
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
4+
iptables -A OUTPUT -p tcp -j DROP

range/layers/intranet/layer.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ packages:
33
configs:
44
- etc/nginx/http.d/default.conf
55
- var/www/localhost/htdocs/index.html
6+
- var/www/localhost/htdocs/creds.txt
67
start: |
78
nginx -g "daemon off;" &

0 commit comments

Comments
 (0)