/
sql.go
152 lines (141 loc) · 3.18 KB
/
sql.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
package checks
import (
"context"
"database/sql"
"fmt"
"math/rand"
"regexp"
"strings"
_ "github.com/go-sql-driver/mysql"
)
type Sql struct {
checkBase
Kind string
Query []queryData
}
type queryData struct {
UseRegex bool
Contains bool
DatabaseExists bool
Database string
Table string
Column string
Output string
}
func (c Sql) Run(teamID uint, boxIp string, res chan Result) {
username, password := getCreds(teamID, c.CredLists, c.Name)
// Run query
q := c.Query[rand.Intn(len(c.Query))]
db, err := sql.Open(c.Kind, fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", username, password, boxIp, c.Port, q.Database))
if err != nil {
res <- Result{
Error: "creating db handle failed",
Debug: "error: " + err.Error() + ", creds " + username + ":" + password,
}
return
}
defer db.Close()
// Check db connection
err = db.PingContext(context.TODO())
if err != nil {
res <- Result{
Error: "db connection or login failed",
Debug: err.Error(),
}
return
}
// Query the DB
// TODO: This is SQL injectable. Figure out Paramerterized queries. not that it really matters...
var rows *sql.Rows
if q.DatabaseExists {
rows, err = db.QueryContext(context.TODO(), fmt.Sprint("SHOW DATABASES;"))
if err != nil {
res <- Result{
Error: "could not query db for database " + q.Database,
Debug: err.Error(),
}
return
}
defer rows.Close()
q.Contains = true
q.Output = q.Database
} else {
rows, err = db.QueryContext(context.TODO(), fmt.Sprintf("SELECT %s FROM %s;", q.Column, q.Table))
if err != nil {
res <- Result{
Error: "could not query db for database " + q.Database + " table " + q.Table + " column " + q.Column,
Debug: err.Error(),
}
return
}
defer rows.Close()
}
var output string
if q.Output != "" {
foundSwitch := false
// Check the rows
for rows.Next() {
// Grab a value
err := rows.Scan(&output)
if err != nil {
res <- Result{
Error: "could not get row values",
Debug: err.Error(),
}
return
}
if q.Contains {
if q.UseRegex {
re := regexp.MustCompile(q.Output)
found := re.Find([]byte(output))
if len(found) != 0 {
foundSwitch = true
break
}
} else {
if strings.Contains(output, q.Output) {
foundSwitch = true
break
}
}
} else {
if q.UseRegex {
re := regexp.MustCompile(q.Output)
if re.Match([]byte(output)) {
foundSwitch = true
break
}
} else {
if strings.TrimSpace(output) == q.Output {
foundSwitch = true
break
}
}
}
}
if !foundSwitch {
var debug string
if q.DatabaseExists {
debug = "database server didn't contain database " + q.Output
} else {
debug = "database " + q.Database + " table " + q.Table + " column " + q.Column + " didn't contain " + q.Output
}
res <- Result{
Error: "query output didn't contain value",
Debug: debug}
return
}
// Check for error in the rows
if rows.Err() != nil {
res <- Result{
Error: "sql rows experienced an error",
Debug: err.Error(),
}
return
}
}
res <- Result{
Status: true,
Debug: "creds used were " + username + ":" + password,
}
}