-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsolver.go
More file actions
132 lines (117 loc) · 3.34 KB
/
Copy pathsolver.go
File metadata and controls
132 lines (117 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main
import (
"encoding/base32"
"encoding/base64"
"encoding/hex"
"fmt"
"net/url"
"strings"
)
// SolveResult contains the result of a local decryption/decoding attempt
type SolveResult struct {
Success bool
Algorithm string
DecodedData string
}
// Solver encapsulates local solving logic
type Solver struct{}
// NewSolver creates a new local solver instance
func NewSolver() *Solver {
return &Solver{}
}
// TryDecode attempts all standard encodings
func (s *Solver) TryDecode(input string) *SolveResult {
// Try Base64
if data, err := base64.StdEncoding.DecodeString(input); err == nil {
// Heuristic: if it decodes to only printable chars, it's likely correct
if isPrintable(data) {
return &SolveResult{Success: true, Algorithm: "Base64", DecodedData: string(data)}
}
}
// Try Hex
if data, err := hex.DecodeString(input); err == nil {
if isPrintable(data) {
return &SolveResult{Success: true, Algorithm: "Hex", DecodedData: string(data)}
}
}
// Try URL
if data, err := url.QueryUnescape(input); err == nil && data != input {
return &SolveResult{Success: true, Algorithm: "URL Encoding", DecodedData: data}
}
// Try Base32
if data, err := base32.StdEncoding.DecodeString(input); err == nil {
if isPrintable(data) {
return &SolveResult{Success: true, Algorithm: "Base32", DecodedData: string(data)}
}
}
// Try Rot13
rot13 := s.Rot13(input)
// Simple check: does it look like a flag or English?
// The prompt implies "Auto-solve" Rot13. We'll just return it if it contains "pico" or similar,
// or we can just return it as a candidate if requested.
// For "Auto-solve", we might need a heuristic.
if strings.Contains(strings.ToLower(rot13.DecodedData), "pico") {
return rot13
}
// Try Caesar Brute Force (looking for flag format)
caesar := s.BruteForceCaesar(input)
if caesar.Success {
return caesar
}
return &SolveResult{Success: false}
}
// Rot13 implementation
func (s *Solver) Rot13(input string) *SolveResult {
var result strings.Builder
for _, r := range input {
switch {
case r >= 'a' && r <= 'z':
result.WriteRune('a' + (r-'a'+13)%26)
case r >= 'A' && r <= 'Z':
result.WriteRune('A' + (r-'A'+13)%26)
default:
result.WriteRune(r)
}
}
return &SolveResult{Success: true, Algorithm: "Rot13", DecodedData: result.String()}
}
// BruteForceCaesar shifts 1-25 looking for "picoCTF{"
func (s *Solver) BruteForceCaesar(input string) *SolveResult {
target := "picoctf" // Case insensitive check
for shift := 1; shift < 26; shift++ {
var result strings.Builder
for _, r := range input {
switch {
case r >= 'a' && r <= 'z':
// Python: chr((ord(char) - 97 + shift) % 26 + 97)
// Go: 'a' + (r-'a'+rune(shift))%26
result.WriteRune('a' + (r-'a'+rune(shift))%26)
case r >= 'A' && r <= 'Z':
result.WriteRune('A' + (r-'A'+rune(shift))%26)
default:
result.WriteRune(r)
}
}
candidate := result.String()
if strings.Contains(strings.ToLower(candidate), target) {
return &SolveResult{
Success: true,
Algorithm: fmt.Sprintf("Caesar Cipher (Shift %d)", shift),
DecodedData: candidate,
}
}
}
return &SolveResult{Success: false}
}
func isPrintable(data []byte) bool {
for _, b := range data {
// Allow some standard whitespace
if b < 32 && b != '\n' && b != '\r' && b != '\t' {
return false
}
if b > 126 {
return false
}
}
return true
}