Merge pull request #3 from Harrison-Wells-Cyber/codex/review-proxy-tool-for-internal-ad-environment

Change authentication method to better work in environments with tls inspection.
This commit is contained in:
Harrison-Wells-Cyber
2026-07-22 15:45:40 -07:00
committed by GitHub
3 changed files with 58 additions and 0 deletions
+19
View File
@@ -160,6 +160,25 @@ connections during high-concurrency tools such as NetExec; the default is 256. W
but host telemetry, PowerShell logging, AMSI, EDR, crash dumps, or pagefile
behavior are outside the loader's control.
### TLS inspection / enterprise decryption
If an authorized enterprise TLS inspection device presents a different leaf
certificate to the Windows agent than the certificate loaded by the VPS server,
agent certificate pinning will fail. The safest fix is to exempt the PS-Proxy
server domain from TLS decryption so the agent sees the VPS certificate directly.
For controlled labs where decryption cannot be bypassed, pass the inspected leaf
certificate SHA-256 DER hash explicitly:
```bash
--agent-cert-pin-override <64-char-sha256-hex-pin>
```
Only use this when you control and trust the inspection device. This pins the
agent to the certificate it actually sees, not the certificate file loaded by the
VPS server.
## Current implementation status
Implemented now:
+19
View File
@@ -34,6 +34,7 @@ func main() {
port := flag.Int("port", 443, "TLS listener port")
cert := flag.String("cert", "", "TLS fullchain PEM; defaults to /etc/letsencrypt/live/<domain>/fullchain.pem")
key := flag.String("key", "", "TLS private key PEM; defaults to /etc/letsencrypt/live/<domain>/privkey.pem")
agentCertPinOverride := flag.String("agent-cert-pin-override", "", "override SHA-256 DER certificate pin embedded in staged agents; use only when an authorized TLS inspection device presents a different leaf cert")
tun := flag.String("tun", "psproxy0", "TUN interface name for the planned netstack data plane")
agentTemplate := flag.String("agent-template", "agent/loader/agent.ps1.tmpl", "PowerShell agent loader template")
agentAssemblyFile := flag.String("agent-assembly-b64-file", "", "file containing compressed/base64 PSProxy.Agent.dll; defaults to release/agent_assembly.b64 when present")
@@ -74,6 +75,13 @@ func main() {
if err != nil {
log.Fatalf("certificate pin failed: %v", err)
}
if *agentCertPinOverride != "" {
pin, err = normalizeCertPin(*agentCertPinOverride)
if err != nil {
log.Fatalf("invalid --agent-cert-pin-override: %v", err)
}
log.Printf("WARNING: using operator-supplied agent certificate pin override")
}
assembly, err := loadAssemblyB64(*agentAssemblyFile)
if err != nil {
log.Fatalf("agent assembly load failed: %v", err)
@@ -708,6 +716,17 @@ type multiFlag []string
func (m *multiFlag) String() string { return strings.Join(*m, ",") }
func (m *multiFlag) Set(v string) error { *m = append(*m, v); return nil }
func normalizeCertPin(pin string) (string, error) {
normalized := strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(strings.TrimSpace(pin), ":", ""), " ", ""))
if len(normalized) != 64 {
return "", fmt.Errorf("pin must be 64 hex characters after removing colons/spaces")
}
if _, err := hex.DecodeString(normalized); err != nil {
return "", fmt.Errorf("pin must be hex: %w", err)
}
return normalized, nil
}
func certPin(path string) (string, error) {
pemBytes, err := os.ReadFile(path)
if err != nil {
+20
View File
@@ -124,3 +124,23 @@ func TestSingleListenerAcceptReturnsEOFAfterFirstConn(t *testing.T) {
t.Fatal("second accept should return EOF")
}
}
func TestNormalizeCertPin(t *testing.T) {
pin := "BC:1D:96:47:91:A5:11:B4:95:26:EC:F2:25:35:37:F6:E6:17:0A:1A:19:4F:45:65:9E:88:0C:A7:A4:3D:6C:02"
got, err := normalizeCertPin(pin)
if err != nil {
t.Fatalf("normalize pin failed: %v", err)
}
want := "bc1d964791a511b49526ecf2253537f6e6170a1a194f45659e880ca7a43d6c02"
if got != want {
t.Fatalf("unexpected normalized pin: %s", got)
}
}
func TestNormalizeCertPinRejectsInvalidPins(t *testing.T) {
for _, pin := range []string{"abc", "zz1d964791a511b49526ecf2253537f6e6170a1a194f45659e880ca7a43d6c02"} {
if _, err := normalizeCertPin(pin); err == nil {
t.Fatalf("expected invalid pin %q to fail", pin)
}
}
}