Skip to content

Commit 7f39933

Browse files
committed
introduce wsb and toolkit installer builders
1 parent 57e3349 commit 7f39933

4 files changed

Lines changed: 428 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@
22

33
All notable changes to RedSand are documented here. Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Note: the artifacts here are Windows Sandbox configs and PowerShell scripts rather than a versioned API, so semver is followed loosely — minor version bumps reflect meaningful additions to the user-facing surface.
44

5-
## [2.0]
5+
## [2.1] — 2026-05-19
6+
7+
### Added
8+
- **`build-wsb.ps1`** — interactive `.wsb` builder. Walks every Windows Sandbox setting (isolation knobs, mapped folders, logon command) and writes a configuration file. Output path is freeform (relative or absolute).
9+
- **`build-toolkit-installer.ps1`** — interactive generator for scoop-based tool-pack installers. Pick buckets and tools, choose global (sandbox / admin) or per-user scope; emits an installer that adapts to the chosen scope (drops `--global` and the admin requirement for per-user).
10+
11+
### Fixed
12+
- **Encoding sweep across every authored script.** Comments contained em-dashes (``) and one arrow (``). Windows PowerShell 5 reads files as Windows-1252 by default; the third byte of those UTF-8 sequences decodes as a smart-quote, which the parser treats as a string delimiter — producing cascading parse errors hundreds of lines below the offender. All occurrences replaced with ASCII equivalents.
13+
- `Set-ExecutionPolicy -Scope LocalMachine` erroring under newer sandbox builds' Group Policy lockout — `setup.ps1` now falls back through scopes and never aborts the rest of the script.
14+
15+
## [2.0] — 2026-05-18
616

717
### Added
818
- **Profiles**`profiles/RedSand-Analysis.wsb` (max-isolation RE / dynamic + static analysis) and `profiles/RedSand-Forensics.wsb` (evidence triage), alongside the existing default. Both default to network off, audio/video/printer/clipboard disabled, ProtectedClient on, and read-only `Input/` + read-write `Output/` host mappings. `profiles/RedSand-Pentest.wsb` is stashed in `.drafts/` pending demand.
@@ -12,9 +22,15 @@ All notable changes to RedSand are documented here. Format based on [Keep a Chan
1222
- **`installAnalysisTools.ps1`** — lightweight scoop pack: HxD, dnSpy, PE-bear, Detect It Easy, x64dbg, System Informer, Wireshark.
1323
- **`installForensicsTools.ps1`** — narrow scoop pack: HxD, ExifTool.
1424
- **`prepareForRedSand.ps1`** — host-side orchestrator. Checks the sandbox feature is enabled, then runs the OnHost downloader scripts (interactive prompt, or `-All` / `-Sysinternals` / `-Zimmerman` flags).
25+
- Gallery section in the README.
26+
- Recursive `.gitignore` entries for macOS clutter (`**/.DS_Store`, `**/._DS_Store`).
1527

1628
### Changed
17-
- Default `RedSand.wsb` moved from repo root to `profiles/RedSand.wsb`. Mapped folder paths updated to `..\Utils\` / `..\Files\`.
29+
- `setup.ps1` now writes a timestamped log to `Desktop\setup.log` for post-mortem diagnostics, falls back gracefully when `Set-ExecutionPolicy -Scope LocalMachine` is blocked by Group Policy (tries `CurrentUser`, then logs and continues regardless), and restarts `explorer.exe` at the end so the dark-theme registry change actually takes effect on the running shell.
30+
- `installChocoAndScoop.ps1` now also installs `git` via scoop (required for `scoop bucket add` to clone bucket repos).
31+
- `installAnalysisTools.ps1` and `installForensicsTools.ps1` self-heal by installing `git` if missing before adding the `extras` bucket.
32+
- `downloadZimmermanTools.ps1` fetches the latest `Get-ZimmermanTools.ps1` directly from Eric Zimmerman's GitHub repo — the backblaze `.zip` shipped a stale copy hardcoded to an `index.md` path that has since 404'd. Also `Push-Location`s into the destination so downloads land in `Utils/Toolkits/Zimmerman/` regardless of caller PWD, and `Unblock-File`s the extracted script to skip PowerShell's Mark-of-the-Web prompt.
33+
- URL liveness CI updated to the new Zimmerman endpoints (`tools.ericzimmermanstools.com` and the GitHub-hosted script).
1834

1935
## [1.1] — 2026-05-17
2036

@@ -26,6 +42,7 @@ All notable changes to RedSand are documented here. Format based on [Keep a Chan
2642
- README rewritten from the GitHub wiki contents, with CI badge and threat-model / WSL caveats section.
2743

2844
### Changed
45+
- Default `RedSand.wsb` moved from repo root to `profiles/RedSand.wsb`. Mapped folder paths updated to `..\Utils\` / `..\Files\`.
2946
- `installREToolkit.ps1` no longer pins the `2022.04` release — fetches latest from the GitHub releases API and handles the `.7z`-wrapped installer introduced in `2026.04`.
3047
- OnHost downloader scripts anchor paths with `$PSScriptRoot` so they work regardless of caller PWD.
3148
- `installChocoAndScoop.ps1` passes `-RunAsAdmin` to Scoop (required since the sandbox runs as admin) and verifies install via on-disk file existence rather than PATH.

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ RedSand/
101101
| `enableSandboxFeature.ps1` | Enables the Windows Sandbox optional feature. Requires admin; may need a reboot. |
102102
| `downloadSysinternalsSuite.ps1` | Downloads SysinternalsSuite into `Utils/Toolkits/SysinternalsSuite/`. |
103103
| `downloadZimmermanTools.ps1` | Fetches Eric Zimmerman's forensics tools into `Utils/Toolkits/Zimmerman/`. |
104+
| `build-wsb.ps1` | Interactive `.wsb` builder. Walks through every Windows Sandbox setting and writes a configuration file. Output path is freeform (relative or absolute). |
105+
| `build-toolkit-installer.ps1` | Interactive generator for scoop-based tool-pack installers (same shape as `installAnalysisTools.ps1`). Pick buckets, list tools, choose global (sandbox / admin) or per-user scope; writes a runnable `.ps1`. |
104106

105107
To run any OnHost script, open PowerShell in the repo root:
106108

@@ -146,6 +148,20 @@ For one-off in-sandbox setup, edit `customScript.ps1` and uncomment its `<Comman
146148

147149
If you don't want a profile's writable `Output/` mapping persisting state on the host, comment out the `Output/` `MappedFolder` block in that wsb (it's marked with an inline comment).
148150

151+
### Custom profiles and tool packs
152+
153+
Two interactive builders generate new `.wsb` profiles and scoop tool-pack installers without hand-editing XML or PowerShell:
154+
155+
```powershell
156+
# Build a custom .wsb (prompts for each isolation knob + mapped folders)
157+
powershell.exe -ExecutionPolicy Bypass -File .\Utils\Scripts\AdditionalScripts\OnHost\build-wsb.ps1
158+
159+
# Generate a scoop-based tool-pack installer
160+
powershell.exe -ExecutionPolicy Bypass -File .\Utils\Scripts\AdditionalScripts\OnHost\build-toolkit-installer.ps1
161+
```
162+
163+
The tool-pack builder asks for install scope — pick **Global** for the sandbox (admin install via scoop's `--global`) or **Per-user** if you're generating something for your everyday machine. The generated script adapts: per-user output drops the `#Requires -RunAsAdministrator` line and the `--global` flag, so the same builder works for both RedSand and standalone use.
164+
149165
## Security notes
150166

151167
A few things worth knowing before you drop sensitive material into the sandbox:
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
#Requires -Version 5.1
2+
$ErrorActionPreference = 'Stop'
3+
4+
# Interactive builder for scoop-based tool-pack installers. Prompts for
5+
# output path, install scope, buckets, and tool list - then writes a script
6+
# that you can run inside a Windows Sandbox (global / admin install) OR
7+
# from any local PowerShell session (per-user install).
8+
#
9+
# Output path is freeform - relative or absolute, anywhere on disk.
10+
11+
12+
# -------- prompt helpers --------
13+
14+
function Read-Option {
15+
param([string]$Prompt, [string[]]$Options, [int]$DefaultIdx = 0)
16+
Write-Host ""
17+
Write-Host $Prompt -ForegroundColor Cyan
18+
for ($i = 0; $i -lt $Options.Count; $i++) {
19+
$marker = if ($i -eq $DefaultIdx) { '*' } else { ' ' }
20+
Write-Host (" {0} {1}) {2}" -f $marker, ($i + 1), $Options[$i])
21+
}
22+
while ($true) {
23+
$resp = Read-Host "Choice [$($DefaultIdx + 1)]"
24+
if ([string]::IsNullOrWhiteSpace($resp)) { return $Options[$DefaultIdx] }
25+
$parsed = 0
26+
if ([int]::TryParse($resp, [ref]$parsed)) {
27+
$idx = $parsed - 1
28+
if ($idx -ge 0 -and $idx -lt $Options.Count) { return $Options[$idx] }
29+
}
30+
Write-Host " Invalid choice; try again." -ForegroundColor Yellow
31+
}
32+
}
33+
34+
function Read-WithDefault {
35+
param([string]$Prompt, [string]$Default)
36+
$val = Read-Host "$Prompt [$Default]"
37+
if ([string]::IsNullOrWhiteSpace($val)) { return $Default }
38+
return $val
39+
}
40+
41+
function Read-YesNo {
42+
param([string]$Prompt, [bool]$Default = $true)
43+
$hint = if ($Default) { '[Y/n]' } else { '[y/N]' }
44+
while ($true) {
45+
$resp = Read-Host "$Prompt $hint"
46+
if ([string]::IsNullOrWhiteSpace($resp)) { return $Default }
47+
switch -Regex ($resp.Trim().ToLower()) {
48+
'^y(es)?$' { return $true }
49+
'^n(o)?$' { return $false }
50+
default { Write-Host " Please answer y or n." -ForegroundColor Yellow }
51+
}
52+
}
53+
}
54+
55+
56+
# -------- flow --------
57+
58+
Write-Host ""
59+
Write-Host "=== RedSand custom toolkit installer builder ===" -ForegroundColor Green
60+
Write-Host "Generates a scoop-based installer .ps1 with your chosen tool list."
61+
Write-Host ""
62+
63+
# Output (any path works - absolute, relative)
64+
$outFile = Read-WithDefault -Prompt 'Output path' -Default 'Utils\Scripts\AdditionalScripts\InSandbox\installCustomTools.ps1'
65+
if ($outFile -notlike '*.ps1') { $outFile = "$outFile.ps1" }
66+
67+
$description = Read-WithDefault -Prompt 'One-line description (for the script header)' -Default 'Custom scoop tool pack'
68+
69+
# Install scope determines --global usage + admin requirement in the emitted script
70+
$scope = Read-Option 'Install scope?' @(
71+
'Global (sandbox / any admin install)',
72+
'Per-user (local non-admin install)'
73+
) 0
74+
$useGlobal = ($scope -like 'Global*')
75+
$globalFlag = if ($useGlobal) { ' --global' } else { '' }
76+
77+
# Buckets
78+
$buckets = @()
79+
Write-Host ""
80+
Write-Host "--- Buckets ---" -ForegroundColor Cyan
81+
Write-Host "Scoop's 'main' bucket is always available; add others as needed."
82+
83+
if (Read-YesNo -Prompt "Add 'extras' bucket?" -Default $true) { $buckets += 'extras' }
84+
foreach ($candidate in 'nirsoft', 'versions', 'java') {
85+
if (Read-YesNo -Prompt "Add '$candidate' bucket?" -Default $false) { $buckets += $candidate }
86+
}
87+
while (Read-YesNo -Prompt 'Add another custom bucket?' -Default $false) {
88+
$name = Read-Host " Bucket name (or 'name <git-url>' for a custom feed)"
89+
if (-not [string]::IsNullOrWhiteSpace($name)) { $buckets += $name.Trim() }
90+
}
91+
92+
# Tools
93+
$tools = @()
94+
Write-Host ""
95+
Write-Host "--- Tools ---" -ForegroundColor Cyan
96+
Write-Host "Enter tool names, comma- or space-separated. Example: hxd, dnspy, x64dbg"
97+
$first = Read-Host 'Tools'
98+
if (-not [string]::IsNullOrWhiteSpace($first)) {
99+
$tools += @($first -split '[,\s]+' | Where-Object { $_ })
100+
}
101+
while (Read-YesNo -Prompt 'Add more (one at a time)?' -Default $false) {
102+
$name = Read-Host ' Tool name'
103+
if (-not [string]::IsNullOrWhiteSpace($name)) { $tools += $name.Trim() }
104+
}
105+
106+
if ($tools.Count -eq 0) {
107+
Write-Host "No tools listed; aborting." -ForegroundColor Yellow
108+
return
109+
}
110+
111+
# Summary + confirm
112+
$resolvedOut = if (Test-Path -IsValid $outFile) { [System.IO.Path]::GetFullPath((Join-Path (Get-Location).Path $outFile)) } else { $outFile }
113+
114+
Write-Host ""
115+
Write-Host "=== Summary ===" -ForegroundColor Green
116+
Write-Host "Output: $outFile"
117+
Write-Host " (full path) $resolvedOut"
118+
Write-Host "Description: $description"
119+
Write-Host "Scope: $scope"
120+
Write-Host "Buckets: $(if ($buckets.Count) { $buckets -join ', ' } else { '(none beyond main)' })"
121+
Write-Host "Tools ($($tools.Count)):"
122+
foreach ($t in $tools) { Write-Host " - $t" }
123+
Write-Host ""
124+
125+
if (-not (Read-YesNo -Prompt 'Write this file?' -Default $true)) {
126+
Write-Host "Aborted." -ForegroundColor Yellow
127+
return
128+
}
129+
130+
131+
# -------- emit the installer script --------
132+
133+
$lines = @()
134+
$lines += '#Requires -Version 5.1'
135+
if ($useGlobal) {
136+
$lines += '#Requires -RunAsAdministrator'
137+
}
138+
$lines += "`$ErrorActionPreference = 'Stop'"
139+
$lines += ''
140+
$lines += "# $description"
141+
$lines += '# Generated by build-toolkit-installer.ps1'
142+
$lines += '#'
143+
if ($useGlobal) {
144+
$lines += '# Global / admin install. Run installChocoAndScoop.ps1 first inside the'
145+
$lines += '# sandbox, or install scoop manually with -RunAsAdmin.'
146+
} else {
147+
$lines += '# Per-user install. Requires scoop already installed (https://scoop.sh).'
148+
}
149+
$lines += ''
150+
$lines += 'if (-not (Get-Command scoop -ErrorAction SilentlyContinue)) {'
151+
$lines += ' throw "scoop not found - install scoop first (https://scoop.sh)"'
152+
$lines += '}'
153+
$lines += ''
154+
$lines += '# Scoop needs git to clone bucket repos; install it if missing'
155+
$lines += 'if (-not (Get-Command git -ErrorAction SilentlyContinue)) {'
156+
$lines += ' Write-Host "Installing git (required for scoop buckets)..." -ForegroundColor Cyan'
157+
$lines += " scoop install$globalFlag git"
158+
$lines += '}'
159+
$lines += ''
160+
foreach ($b in $buckets) {
161+
$lines += "scoop bucket add $b"
162+
}
163+
if ($buckets.Count -gt 0) { $lines += '' }
164+
165+
$lines += "`$tools = @("
166+
for ($i = 0; $i -lt $tools.Count; $i++) {
167+
$sep = if ($i -eq $tools.Count - 1) { '' } else { ',' }
168+
$lines += " '$($tools[$i])'$sep"
169+
}
170+
$lines += ')'
171+
$lines += ''
172+
$lines += 'foreach ($tool in $tools) {'
173+
$lines += ' Write-Host "Installing $tool..." -ForegroundColor Cyan'
174+
$lines += " scoop install$globalFlag `$tool"
175+
$lines += ' if ($LASTEXITCODE -ne 0) {'
176+
$lines += ' Write-Warning "scoop returned exit code $LASTEXITCODE installing $tool"'
177+
$lines += ' }'
178+
$lines += '}'
179+
$lines += ''
180+
$lines += 'Write-Host "Tools installed." -ForegroundColor Green'
181+
182+
# Write
183+
$parentDir = Split-Path -Parent $outFile
184+
if ($parentDir -and -not (Test-Path $parentDir)) {
185+
New-Item -ItemType Directory -Path $parentDir -Force | Out-Null
186+
}
187+
Set-Content -Path $outFile -Value ($lines -join [Environment]::NewLine) -Encoding UTF8
188+
189+
Write-Host ""
190+
Write-Host "Wrote $outFile" -ForegroundColor Green
191+
Write-Host " (full path) $resolvedOut"
192+
Write-Host ""
193+
if ($useGlobal) {
194+
Write-Host "Run inside the sandbox (after installChocoAndScoop.ps1):" -ForegroundColor Cyan
195+
} else {
196+
Write-Host "Run from any PowerShell session (scoop must be installed):" -ForegroundColor Cyan
197+
}
198+
Write-Host " powershell.exe -ExecutionPolicy Bypass -File `"$resolvedOut`""

0 commit comments

Comments
 (0)