lifedebugger commited on
Commit
7dccad9
·
verified ·
1 Parent(s): d7d2003

Create main.go

Browse files
Files changed (1) hide show
  1. main.go +128 -0
main.go ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package main
2
+
3
+ import (
4
+ "database/sql"
5
+ "fmt"
6
+ "log"
7
+ "net/http"
8
+ "os"
9
+
10
+ _ "github.com/lib/pq"
11
+ )
12
+
13
+ // User represents the database structure we are querying
14
+ type User struct {
15
+ ID int
16
+ Username string
17
+ Flag string
18
+ }
19
+
20
+ // connectDB handles the connection to Supabase/Postgres
21
+ func connectDB() (*sql.DB, error) {
22
+ connStr := os.Getenv("DATABASE_URL")
23
+ if connStr == "" {
24
+ return nil, fmt.Errorf("DATABASE_URL environment variable is not set")
25
+ }
26
+ return sql.Open("postgres", connStr)
27
+ }
28
+
29
+ func main() {
30
+ // 1. Serve static HTML for the login page
31
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
32
+ html := `
33
+ <!DOCTYPE html>
34
+ <html>
35
+ <head>
36
+ <title>CTF Login Challenge</title>
37
+ <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
38
+ </head>
39
+ <body class="bg-gray-900 text-white flex items-center justify-center h-screen">
40
+ <div class="bg-gray-800 p-8 rounded shadow-lg w-96">
41
+ <h1 class="text-2xl mb-4 text-center font-bold text-red-500">RESTRICTED AREA</h1>
42
+ <p class="text-gray-400 mb-6 text-center text-sm">Enter admin credentials to retrieve the flag.</p>
43
+ <form action="/login" method="POST" class="space-y-4">
44
+ <div>
45
+ <label class="block text-sm font-medium">Username</label>
46
+ <input type="text" name="username" class="w-full p-2 bg-gray-700 rounded border border-gray-600 focus:border-red-500 outline-none" placeholder="admin">
47
+ </div>
48
+ <div>
49
+ <label class="block text-sm font-medium">Password</label>
50
+ <input type="password" name="password" class="w-full p-2 bg-gray-700 rounded border border-gray-600 focus:border-red-500 outline-none" placeholder="••••••">
51
+ </div>
52
+ <button type="submit" class="w-full bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition">ACCESS SYSTEM</button>
53
+ </form>
54
+ <div class="mt-4 text-xs text-gray-600 text-center">System Version: 1.0.0-VULN</div>
55
+ </div>
56
+ </body>
57
+ </html>
58
+ `
59
+ w.Header().Set("Content-Type", "text/html")
60
+ w.Write([]byte(html))
61
+ })
62
+
63
+ // 2. The Vulnerable Login Endpoint
64
+ http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
65
+ if r.Method != http.MethodPost {
66
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
67
+ return
68
+ }
69
+
70
+ username := r.FormValue("username")
71
+ password := r.FormValue("password")
72
+
73
+ db, err := connectDB()
74
+ if err != nil {
75
+ http.Error(w, "Database connection failed", http.StatusInternalServerError)
76
+ log.Println("DB Error:", err)
77
+ return
78
+ }
79
+ defer db.Close()
80
+
81
+ // --- THE VULNERABILITY IS HERE ---
82
+ // We are directly formatting the string with user input.
83
+ // A user can input "' OR '1'='1" to bypass the check.
84
+ query := fmt.Sprintf("SELECT id, username, flag FROM users WHERE username = '%s' AND password = '%s'", username, password)
85
+
86
+ // Log the query to the console (useful for debugging the CTF/seeing the injection)
87
+ log.Printf("Executing Query: %s\n", query)
88
+
89
+ var user User
90
+ // We use QueryRow because we expect one result for a login, but the injection might return the first row (admin)
91
+ err = db.QueryRow(query).Scan(&user.ID, &user.Username, &user.Flag)
92
+
93
+ if err != nil {
94
+ if err == sql.ErrNoRows {
95
+ w.WriteHeader(http.StatusUnauthorized)
96
+ w.Write([]byte(`
97
+ <div style="color: red; text-align: center; margin-top: 50px; font-family: monospace;">
98
+ <h1>ACCESS DENIED</h1>
99
+ <p>Invalid credentials.</p>
100
+ <a href="/" style="color: white;">Try Again</a>
101
+ </div>
102
+ `))
103
+ } else {
104
+ http.Error(w, "Query error: "+err.Error(), http.StatusInternalServerError)
105
+ }
106
+ return
107
+ }
108
+
109
+ // If successful (or injected successfully)
110
+ w.WriteHeader(http.StatusOK)
111
+ fmt.Fprintf(w, `
112
+ <div style="color: #4ade80; text-align: center; margin-top: 50px; font-family: monospace; background: #111; padding: 20px;">
113
+ <h1>ACCESS GRANTED</h1>
114
+ <p>Welcome, %s</p>
115
+ <p style="font-size: 24px; border: 1px dashed #4ade80; display: inline-block; padding: 10px;">FLAG: %s</p>
116
+ </div>
117
+ `, user.Username, user.Flag)
118
+ })
119
+
120
+ // Hugging Face Spaces usually serves on port 7860
121
+ port := os.Getenv("PORT")
122
+ if port == "" {
123
+ port = "7860"
124
+ }
125
+
126
+ log.Printf("CTF Challenge listening on port %s", port)
127
+ log.Fatal(http.ListenAndServe(":"+port, nil))
128
+ }