fix:check logic

#170
This commit is contained in:
samwaf
2025-03-04 14:53:40 +08:00
parent 6fcf3e8570
commit e68c1e809d
10 changed files with 162 additions and 25 deletions

View File

@@ -4,6 +4,7 @@ type WebLog struct {
WafInnerDFlag string `json:"waf_inner_dflag"` //日志队列处理方式
HOST string `json:"host"`
URL string `json:"url"`
RawQuery string `json:"raw_query"` //原始URL查询
REFERER string `json:"referer"`
USER_AGENT string `json:"user_agent"`
METHOD string `json:"method"`

View File

@@ -0,0 +1,58 @@
package libinjection
import (
"net/url"
"regexp"
"strings"
)
// HasDirTraversal 检测URL是否存在目录穿越漏洞
func HasDirTraversal(rawURL string) bool {
// 解析URL
parsedURL, err := url.Parse(rawURL)
if err != nil {
return false
}
// 定义路径穿越特征正则表达式
pattern := `(\.\./|\.\.\\|%2e%2e/|%2e%2e\\)`
regex := regexp.MustCompile(pattern)
// 检查URL路径部分
path := parsedURL.Path
if checkComponent(path, regex) {
return true
}
// 检查查询参数值
query := parsedURL.Query()
for _, values := range query {
for _, value := range values {
// 解码URL编码后再检查防止%2e%2e%2f绕过
decodedValue, err := url.QueryUnescape(value)
if err != nil {
decodedValue = value // 如果解码失败,使用原始值
}
if checkComponent(decodedValue, regex) {
return true
}
}
}
return false
}
// 检查单个组件是否包含恶意特征
func checkComponent(component string, regex *regexp.Regexp) bool {
// 检查是否包含路径遍历模式
if regex.MatchString(component) {
return true
}
// 额外检查Windows路径特征
if strings.Contains(component, "..\\") {
return true
}
return false
}

View File

@@ -0,0 +1,22 @@
package libinjection
import (
"fmt"
"testing"
)
func TestHasDirTraversal(t *testing.T) {
// 测试用例
testURLs := []string{
"http://example.com/download?file=../../etc/passwd", // 应检测到
"http://example.com/?id=../../../../etc/passwd", // 应检测到
"http://example.com/../../secret.txt", // 应检测到
"http://example.com/?path=%2e%2e%2fetc%2fpasswd", // 应检测到URL编码的../
"http://example.com/valid?file=doc.pdf", // 正常URL
"http://example.com/?data=..\\Windows\\system.ini", // 检测Windows路径
}
for _, u := range testURLs {
fmt.Printf("检测URL: %-50s => 存在漏洞: %t\n", u, HasDirTraversal(u))
}
}

View File

@@ -34,10 +34,11 @@ type Hosts struct {
}
type HostsDefense struct {
DEFENSE_BOT int `json:"bot"` //防御-虚假BOT
DEFENSE_SQLI int `json:"sqli"` //防御-Sql注入
DEFENSE_XSS int `json:"xss"` //防御-xss攻击
DEFENSE_SCAN int `json:"scan"` //防御-scan工具扫描
DEFENSE_RCE int `json:"rce"` //防御-scan工具扫描
DEFENSE_SENSITIVE int `json:"sensitive"` //敏感词检测
DEFENSE_BOT int `json:"bot"` //防御-虚假BOT
DEFENSE_SQLI int `json:"sqli"` //防御-Sql注入
DEFENSE_XSS int `json:"xss"` //防御-xss攻击
DEFENSE_SCAN int `json:"scan"` //防御-scan工具扫描
DEFENSE_RCE int `json:"rce"` //防御-scan工具扫描
DEFENSE_SENSITIVE int `json:"sensitive"` //敏感词检测
DEFENSE_DIR_TRAVERSAL int `json:"traversal"` //目录穿越检测
}

View File

@@ -0,0 +1,43 @@
package wafenginecore
import (
"SamWaf/innerbean"
"SamWaf/libinjection-go"
"SamWaf/model/detection"
"SamWaf/model/wafenginmodel"
"net/http"
"net/url"
)
// CheckDirTraversal 穿越漏洞检测
func (waf *WafEngine) CheckDirTraversal(r *http.Request, weblogbean *innerbean.WebLog, formValue url.Values, hostTarget *wafenginmodel.HostSafe, globalHostTarget *wafenginmodel.HostSafe) detection.Result {
result := detection.Result{
JumpGuardResult: false,
IsBlock: false,
Title: "",
Content: "",
}
var flag = false
//检测sql注入
if libinjection.HasDirTraversal(weblogbean.RawQuery) ||
libinjection.HasDirTraversal(weblogbean.BODY) {
flag = true
}
if flag == false {
for _, value := range formValue {
for _, v := range value {
if libinjection.HasDirTraversal(v) {
flag = true
}
}
}
}
if flag == true {
weblogbean.RISK_LEVEL = 2
result.IsBlock = true
result.Title = "目录穿越漏洞"
result.Content = "请正确访问"
return result
}
return result
}

View File

@@ -22,7 +22,7 @@ func (waf *WafEngine) CheckSql(r *http.Request, weblogbean *innerbean.WebLog, fo
}
var sqlFlag = false
//检测sql注入
if libinjection.IsSQLiNotReturnPrint(weblogbean.URL) ||
if libinjection.IsSQLiNotReturnPrint(weblogbean.RawQuery) ||
libinjection.IsSQLiNotReturnPrint(weblogbean.BODY) ||
libinjection.IsSQLiNotReturnPrint(weblogbean.POST_FORM) {
sqlFlag = true

View File

@@ -21,7 +21,7 @@ func (waf *WafEngine) CheckXss(r *http.Request, weblogbean *innerbean.WebLog, fo
Content: "",
}
var xssFlag = false
if libinjection.IsXSS(weblogbean.URL) ||
if libinjection.IsXSS(weblogbean.RawQuery) ||
libinjection.IsXSS(weblogbean.POST_FORM) {
xssFlag = true
}

View File

@@ -183,11 +183,12 @@ func (waf *WafEngine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
currentDay, _ := strconv.Atoi(time.Now().Format("20060102"))
//URL 解码
enEscapeUrl := wafhttpcore.WafHttpCoreUrlEncode(r.RequestURI, 100)
deRawQueryUrl := wafhttpcore.WafHttpCoreUrlEncode(r.URL.RawQuery, 10)
datetimeNow := time.Now()
weblogbean := innerbean.WebLog{
HOST: host,
URL: enEscapeUrl,
URL: r.RequestURI,
RawQuery: deRawQueryUrl,
REFERER: r.Referer(),
USER_AGENT: r.UserAgent(),
METHOD: r.Method,
@@ -287,12 +288,13 @@ func (waf *WafEngine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
hostDefense := model.HostsDefense{
DEFENSE_BOT: 1,
DEFENSE_SQLI: 1,
DEFENSE_XSS: 1,
DEFENSE_SCAN: 1,
DEFENSE_RCE: 1,
DEFENSE_SENSITIVE: 1,
DEFENSE_BOT: 1,
DEFENSE_SQLI: 1,
DEFENSE_XSS: 1,
DEFENSE_SCAN: 1,
DEFENSE_RCE: 1,
DEFENSE_SENSITIVE: 1,
DEFENSE_DIR_TRAVERSAL: 1,
}
err := json.Unmarshal([]byte(hostTarget.Host.DEFENSE_JSON), &hostDefense)
if err != nil {
@@ -328,6 +330,12 @@ func (waf *WafEngine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
}
//目录穿越检测
if hostDefense.DEFENSE_DIR_TRAVERSAL == 1 {
if handleBlock(waf.CheckDirTraversal) {
return
}
}
//检测CC
if handleBlock(waf.CheckCC) {
return

View File

@@ -3,12 +3,22 @@ package wafhttpcore
import (
"SamWaf/libinjection-go"
"fmt"
"net/url"
"testing"
)
func TestSql(t *testing.T) {
payload := "data/index.html?id=1 and (select top 1 count(*) from admin where unicode(substring(a,1,1))=asc%E5%80%BC%20and%20id=1)%3E0"
payload := "id=1+and+1=2+union+select+1"
decodedValue, err := url.QueryUnescape(payload)
sqlB, sqlstring := libinjection.IsSQLi(payload)
fmt.Println(sqlB, sqlstring)
payLoadReturnPrint := libinjection.IsSQLiNotReturnPrint(payload)
fmt.Println(fmt.Sprintf("payload=%v Result:%v", payload, payLoadReturnPrint))
decodepayLoadReturnPrint := libinjection.IsSQLiNotReturnPrint(decodedValue)
if err != nil {
fmt.Println(fmt.Sprintf("decodePayload=%v Result:%v QueryUnescapeErr:%v", decodedValue, decodepayLoadReturnPrint, err))
} else {
fmt.Println(fmt.Sprintf("decodePayload=%v Result:%v ", decodedValue, decodepayLoadReturnPrint))
}
}

View File

@@ -3,16 +3,10 @@ package wafhttpcore
import (
"SamWaf/common/zlog"
"net/url"
"strings"
)
// 逆向编码处理
func WafHttpCoreUrlEncode(encoded string, maxDepth int) string {
// 如果没有编码格式,直接返回
if !strings.Contains(encoded, "%") {
return encoded
}
// 限制递归的最大深度,防止无限递归
if maxDepth <= 0 {
return encoded // 达到最大递归深度时返回原始字符串