Commit 9838a846 authored by qiuqunfeng's avatar qiuqunfeng
Browse files

create waf

parent cb8cd6a0
...@@ -29,14 +29,27 @@ LICENSE_SECRET?=sit ...@@ -29,14 +29,27 @@ LICENSE_SECRET?=sit
## 指定bin目录 ## 指定bin目录
BIN_DIR = $(shell pwd)/bin/ BIN_DIR = $(shell pwd)/bin/
GOBIN ?= go
.PHONY: help .PHONY: help
help: help:
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//' @fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
download:
$(GOBIN) mod tidy
.PHONY: build
build: download
@echo "build waf-console"
$(GOBIN) build -v \
-tags=jsoniter -o dist/waf-console gitlab.com/tensorsecurity-rd/waf-console/cmd
#upx --lzma --best dist/waf-console
.PHONY: waf-console .PHONY: waf-console
waf-console: waf-console:
@echo "build waf-console" @echo "build waf-console"
go build -v \ $(GOBIN) build -v \
-tags=jsoniter -o dist/waf-console gitlab.com/tensorsecurity-rd/waf-console/cmd -tags=jsoniter -o dist/waf-console gitlab.com/tensorsecurity-rd/waf-console/cmd
#upx --lzma --best dist/waf-console #upx --lzma --best dist/waf-console
docker build -t $(REPOPREFIX)/waf-console:$(IMAGETAG) -f ./build/Dockerfile . docker build -t $(REPOPREFIX)/waf-console:$(IMAGETAG) -f ./build/Dockerfile .
...@@ -5,19 +5,18 @@ import ( ...@@ -5,19 +5,18 @@ import (
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gitlab.com/security-rd/go-pkg/logging" "github.com/rs/zerolog/log"
"gitlab.com/tensorsecurity-rd/waf-console/internal/config" "gitlab.com/tensorsecurity-rd/waf-console/internal/config"
"gitlab.com/tensorsecurity-rd/waf-console/internal/utils" "gitlab.com/tensorsecurity-rd/waf-console/internal/utils"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/generated/clientset/versioned"
"gorm.io/gorm" "gorm.io/gorm"
) )
func SetRouters(db *gorm.DB, client *versioned.Clientset) *gin.Engine { func SetRouters(db *gorm.DB, clusterClientManager *utils.ClusterClientManager) *gin.Engine {
var engine *gin.Engine var engine *gin.Engine
if !config.Conf.Debug { if !config.Conf.Debug {
// 生产模式 // 生产模式
logging.Get().Info().Msg("release mode") log.Info().Msg("release mode")
engine = ReleaseRouter() engine = ReleaseRouter()
engine.Use( engine.Use(
// middleware.RequestCostHandler(), // middleware.RequestCostHandler(),
...@@ -27,7 +26,7 @@ func SetRouters(db *gorm.DB, client *versioned.Clientset) *gin.Engine { ...@@ -27,7 +26,7 @@ func SetRouters(db *gorm.DB, client *versioned.Clientset) *gin.Engine {
) )
} else { } else {
// 开发调试模式 // 开发调试模式
logging.Get().Info().Msg("debug mode") log.Info().Msg("debug mode")
engine = gin.New() engine = gin.New()
engine.Use( engine.Use(
// middleware.RequestCostHandler(), // middleware.RequestCostHandler(),
...@@ -62,7 +61,7 @@ func SetRouters(db *gorm.DB, client *versioned.Clientset) *gin.Engine { ...@@ -62,7 +61,7 @@ func SetRouters(db *gorm.DB, client *versioned.Clientset) *gin.Engine {
// }, // },
// // BearerToken: "1234567890", // // BearerToken: "1234567890",
// }) // })
SetWafRouter(engine, client, db) SetWafRouter(engine, clusterClientManager, db)
// 统一处理 404 // 统一处理 404
engine.NoRoute(func(c *gin.Context) { engine.NoRoute(func(c *gin.Context) {
......
...@@ -3,16 +3,21 @@ package api ...@@ -3,16 +3,21 @@ package api
import ( import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gitlab.com/tensorsecurity-rd/waf-console/internal/controller" "gitlab.com/tensorsecurity-rd/waf-console/internal/controller"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/generated/clientset/versioned" "gitlab.com/tensorsecurity-rd/waf-console/internal/utils"
"gorm.io/gorm" "gorm.io/gorm"
) )
func SetWafRouter(e *gin.Engine, client *versioned.Clientset, db *gorm.DB) { func SetWafRouter(e *gin.Engine, clusterClientManager *utils.ClusterClientManager, db *gorm.DB) {
v1 := e.Group("v1/api") v1 := e.Group("v1/api/waf")
wafController := controller.NewWafController(client, db) wafController := controller.NewWafController(clusterClientManager, db)
v1.GET("waf/:gateway_name", wafController.Waf) v1.GET("/:region_code/:namespace/:gateway_name", wafController.Waf)
v1.POST("waf", wafController.CreateWaf) v1.POST("/", wafController.CreateWaf)
v1.PUT("mode", wafController.UpdateMode) v1.PUT("mode", wafController.UpdateMode)
v1.PUT("rules", wafController.UpdateRule)
v1.PUT("listener/enable", wafController.EnableListenerWaf)
v1.PUT("gateway/enable", wafController.EnableGatewayWaf)
v1.DELETE("listener/:region_code/:namespace/:gateway_name/:port", wafController.DeleteListenerWaf)
v1.DELETE("gateway/:region_code/:namespace/:gateway_name", wafController.DeleteGatewayWaf)
v1.POST("debug/savecatagory", wafController.SaveRuleCategoryToDB) v1.POST("debug/savecatagory", wafController.SaveRuleCategoryToDB)
} }
...@@ -5,9 +5,10 @@ import ( ...@@ -5,9 +5,10 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"gitlab.com/security-rd/go-pkg/logging"
"gitlab.com/tensorsecurity-rd/waf-console/api" "gitlab.com/tensorsecurity-rd/waf-console/api"
"gitlab.com/tensorsecurity-rd/waf-console/internal/utils"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/generated/clientset/versioned" "gitlab.com/tensorsecurity-rd/waf-console/pkg/generated/clientset/versioned"
"gorm.io/driver/mysql" "gorm.io/driver/mysql"
"gorm.io/gorm" "gorm.io/gorm"
...@@ -22,7 +23,7 @@ func NewRootCommand() *cobra.Command { ...@@ -22,7 +23,7 @@ func NewRootCommand() *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
config := LoadConfig() config := LoadConfig()
debugMode := os.Getenv("DEBUG_MODE") debugMode := os.Getenv("DEBUG_MODE")
logging.Get().Info().Msgf("DEBUG_MODE: %s", debugMode) log.Info().Msgf("DEBUG_MODE: %s", debugMode)
if debugMode == "true" { if debugMode == "true" {
config.Debug = true config.Debug = true
// config.Conf.Debug = true // config.Conf.Debug = true
...@@ -40,30 +41,43 @@ func NewRootCommand() *cobra.Command { ...@@ -40,30 +41,43 @@ func NewRootCommand() *cobra.Command {
panic("dbConfig is nil") panic("dbConfig is nil")
} }
caData, err := base64.StdEncoding.DecodeString(config.RegionConfigs[0].CAData) clusterClientManager := utils.NewClusterClientManager()
if err != nil { for _, regionConfig := range config.RegionConfigs {
panic(err) var caData []byte
} var clientCertData []byte
clientCertData, err := base64.StdEncoding.DecodeString(config.RegionConfigs[0].ClientCertData) var clientKeyData []byte
if err != nil { if regionConfig.CAData != "" {
panic(err) caData, err = base64.StdEncoding.DecodeString(regionConfig.CAData)
} if err != nil {
clientKeyData, err := base64.StdEncoding.DecodeString(config.RegionConfigs[0].ClientKeyData) panic(err)
if err != nil { }
panic(err) }
if regionConfig.ClientCertData != "" {
clientCertData, err = base64.StdEncoding.DecodeString(regionConfig.ClientCertData)
if err != nil {
panic(err)
}
}
if regionConfig.ClientKeyData != "" {
clientKeyData, err = base64.StdEncoding.DecodeString(regionConfig.ClientKeyData)
if err != nil {
panic(err)
}
}
client := versioned.NewForConfigOrDie(&rest.Config{
Host: regionConfig.ApiServer,
TLSClientConfig: rest.TLSClientConfig{
Insecure: regionConfig.Insecure,
CAData: caData,
CertData: clientCertData,
KeyData: clientKeyData,
},
// BearerToken: "1234567890",
})
clusterClientManager.AddClient(regionConfig.RegionCode, client)
} }
client := versioned.NewForConfigOrDie(&rest.Config{
Host: config.RegionConfigs[0].ApiServer,
TLSClientConfig: rest.TLSClientConfig{
Insecure: false,
CAData: caData,
CertData: clientCertData,
KeyData: clientKeyData,
},
// BearerToken: "1234567890",
})
e := api.SetRouters(db, client) e := api.SetRouters(db, clusterClientManager)
return e.Run(":8080") return e.Run(":8080")
}, },
} }
......
...@@ -3,7 +3,7 @@ package app ...@@ -3,7 +3,7 @@ package app
import ( import (
"os" "os"
"gitlab.com/security-rd/go-pkg/logging" "github.com/rs/zerolog/log"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
...@@ -36,6 +36,7 @@ type RegionConfig struct { ...@@ -36,6 +36,7 @@ type RegionConfig struct {
Token string `yaml:"token"` Token string `yaml:"token"`
ClientCertData string `yaml:"client_cert_data"` ClientCertData string `yaml:"client_cert_data"`
ClientKeyData string `yaml:"client_key_data"` ClientKeyData string `yaml:"client_key_data"`
Insecure bool `yaml:"insecure"`
} }
func LoadConfig() *Config { func LoadConfig() *Config {
...@@ -46,13 +47,13 @@ func LoadConfig() *Config { ...@@ -46,13 +47,13 @@ func LoadConfig() *Config {
data, err := os.ReadFile(configFile) data, err := os.ReadFile(configFile)
if err != nil { if err != nil {
logging.Get().Error().Err(err).Msgf("Failed to read config file: %s", configFile) log.Err(err).Msgf("Failed to read config file: %s", configFile)
return nil return nil
} }
var config Config var config Config
if err := yaml.Unmarshal(data, &config); err != nil { if err := yaml.Unmarshal(data, &config); err != nil {
logging.Get().Error().Err(err).Msg("Failed to parse config file") log.Err(err).Msg("Failed to parse config file")
return nil return nil
} }
// 如果config.DBConfig为nil,则使用默认值 // 如果config.DBConfig为nil,则使用默认值
......
...@@ -4,7 +4,7 @@ import ( ...@@ -4,7 +4,7 @@ import (
"os" "os"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"gitlab.com/security-rd/go-pkg/logging" "github.com/rs/zerolog/log"
"gitlab.com/tensorsecurity-rd/waf-console/cmd/app" "gitlab.com/tensorsecurity-rd/waf-console/cmd/app"
) )
...@@ -14,14 +14,13 @@ const ( ...@@ -14,14 +14,13 @@ const (
) )
func main() { func main() {
logLevel := zerolog.InfoLevel
logging.Get().SetLevel(logLevel) zerolog.SetGlobalLevel(zerolog.InfoLevel)
logging.Get().Info().Msg("starting gateway") log.Info().Msg("starting gateway")
rootCmd := app.NewRootCommand() rootCmd := app.NewRootCommand()
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
logging.Get().Err(err) log.Err(err)
os.Exit(-1) os.Exit(-1)
} }
} }
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: testaaa-lsnr-aaaa
namespace: tensorsec
labels:
apigateway: testaaa
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- "*"
port:
name: http2-9999
number: 9999
protocol: HTTP2
\ No newline at end of file
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: waf-console name: tensorsec-waf-console
spec: spec:
selector: selector:
matchLabels: matchLabels:
app: waf-console app: tensorsec-waf-console
template: template:
metadata: metadata:
labels: labels:
app: waf-console app: tensorsec-waf-console
app.kubernetes.io/name: waf-console
spec: spec:
imagePullSecrets:
- name: harbor-admin-secret
containers: containers:
- name: waf-console - name: waf-console
image: harbor.tensorsecurity.com/tensorsecurity/waf-console:testcn image: harbor.tensorsecurity.com/tensorsecurity/waf-console:testcn
imagePullPolicy: Always
resources: resources:
limits: limits:
memory: "128Mi" memory: "128Mi"
...@@ -36,10 +40,10 @@ spec: ...@@ -36,10 +40,10 @@ spec:
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: waf-console name: tensorsec-waf-console
spec: spec:
selector: selector:
app: waf-console app: tensorsec-waf-console
ports: ports:
- port: 8080 - port: 8080
targetPort: 8080 targetPort: 8080
- category_id: c_02
category:
en: SQL injection detection
zh: SQL 注入检测
description:
en: In the implementation of the website, the filtering of input parameters is not strict, resulting in the illegal acquisition of the contents of the SQL database.
zh: 在网站实现上,对于输入参数过滤不严,导致 SQL 数据库的内容被非法获取。
rules:
- id: 302001
level: 1
name: SQLI-BASE-Having
type: SQLI
description: 检测条件类SQL注入攻击
expr: ((?:[\s()]case\s*?\()|(?:\)\s*?like\s*?\()|(?:having\s*?[^\s]+\s*?[^\w\s])|(?:if\s?\([\d\w]\s*?[=<>~]))
mode: match(urlDecode(header_uri|body_buf))
- id: 302002
level: 1
name: SQLI-BASE-Sleeping
type: SQLI
description: 检测时延类SQL注入攻击
expr: ((sleep\((\s*?)(\d*?)(\s*?)\)|benchmark\((.*?)\,(.*?)\)))
mode: match(urlDecode(header_uri|body_buf))
- id: 302003
level: 2
name: SQLI-BASE-PRIV
type: SQLI
description: 检测通过SQL注入提权,文件读写等行为
expr: ((?:\s*?(?:exec|execute).*?(?:\W)xp_cmdshell)|(?:[\"'`]\s*?!\s*?[\"'`\w])|(?:from\W+information_schema\W)|(?:(?:(?:current_)?user|database|schema|connection_id)\s*?\([^\)]*?)|(?:[\"'`];?\s*?(?:select|union|having)\b\s*?[^\s])|(?:\wiif\s*?\()|(?:(?:exec|execute)\s+master\.)|(?:union select @)|(?:union[\w(\s]*?select)|(?:select.*?\w?user\()|(?:into[\s+]+(?:dump|out)file\s*?[\"'`]))
mode: match(urlDecode(header_uri|body_buf))
- id: 302004
level: 2
name: SQLI-BASE-RW
type: SQLI
description: 常见敏感数据库读取类行为
expr: ((?:m(?:s(?:ysaccessobjects|ysaces|ysobjects|ysqueries|ysrelationships|ysaccessstorage|ysaccessxml|ysmodules|ysmodules2|db)|aster\.\.sysdatabases|ysql\.db)\b|s(?:ys(?:\.database_name|aux)\b|chema(?:\W*\(|_name\b)|qlite(_temp)?_master\b)|d(?:atabas|b_nam)e\W*\(|information_schema\b|pg_(catalog|toast)\b|northwind\b|tempdb\b))
mode: match(urlDecode(header_uri|body_buf))
- id: 302005
level: 1
name: SQLI-BASE-Union
type: SQLI
description: 检测联合查询类SQL注入攻击
expr: ((?:(union(.*?)select(.*?)from)))
mode: match(urlDecode(header_uri|body_buf))
- id: 302006
level: 3
name: SQLI-BASE-MongoDB
type: SQLI
description: 检测MongoDB SQL注入行为
expr: ((?:\[\$(?:ne|eq|lte?|gte?|n?in|mod|all|size|exists|type|slice|x?or|div|like|between|and)\]))
mode: match(urlDecode(header_uri|body_buf))
- id: 302007
level: 3
name: SQLI-BASE-Procedure
type: SQLI
description: 检测Mysql与PostgreSQL基于存储过程的注入行为
expr: ((?:procedure\s+analyse\s*?\()|(?:;\s*?(declare|open)\s+[\w-]+)|(?:create\s+(procedure|function)\s*?\w+\s*?\(\s*?\)\s*?-)|(?:declare[^\w]+[@#]\s*?\w+)|(exec\s*?\(\s*?@))
mode: match(urlDecode(header_uri|body_buf))
- id: 302008
level: 1
name: SQLI-BASE-Concat
type: SQLI
description: 检测基于concat及文件读取类SQL注入行为
expr: ((?:[\d\W]\s+as\s*?[\"'`\w]+\s*?from)|(?:^[\W\d]+\s*?(?:union|select|create|rename|truncate|load|alter|delete|update|insert|desc)\b)|(?:(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s+(?:(?:group_)concat|char|load_file)\s?\(?)|(?:end\s*?\);)|([\"'`]\s+regexp\W)|(?:[\s(]load_file\s*?\())
mode: match(urlDecode(header_uri|body_buf))
- id: 302009
level: 1
name: SQLI-BASE-Try
type: SQLI
description: 检测SQL注入尝试行为
expr: (^[\"'`;]+|[\"'`]+$)
mode: match(urlDecode(header_uri|body_buf))
- id: 302010
level: 1
name: SQLI-BASE-Operater
type: SQLI
description: 检测SQL常见操作符
expr: ((\!\=|\&\&|\|\||\bxor\b|\brlike\b|\bregexp\b|\bisnull\b)|(?:not\s+between\s+0\s+and)|(?:is\s+null)|(like\s+null)|(?:(?:^|\W)in[+\s]*\([\s\d\"]+[^()]*\))|(?:\bxor\b|<>|rlike(?:\s+binary)?)|(?:regexp\s+binary))
mode: match(urlDecode(header_uri|body_buf))
- id: 302011
level: 3
name: SQLI-BASE-DBname
type: SQLI
description: 常见数据库名检测
expr: ((?:m(?:s(?:ysaccessobjects|ysaces|ysobjects|ysqueries|ysrelationships|ysaccessstorage|ysaccessxml|ysmodules|ysmodules2|db)|aster\.\.sysdatabases|ysql\.db)\b|s(?:ys(?:\.database_name|aux)\b|chema(?:\W*\(|_name\b)|qlite(_temp)?_master\b)|d(?:atabas|b_nam)e\W*\(|information_schema\b|pg_(catalog|toast)\b|northwind\b|tempdb\b))
mode: match(urlDecode(header_uri|body_buf))
- id: 302012
level: 2
name: SQLI-BASE-MSdos
type: SQLI
description: 检测mysql字符转换及mssql dos攻击
expr: ((?:alter\s*?\w+.*?(?:character|char)\s+set\s+\w+)|([\"'`];*?\s*?waitfor\s+(?:time|delay)\s+[\"'`])|(?:[\"'`];.*?:\s*?goto))
mode: match(urlDecode(header_uri|body_buf))
- id: 302013
level: 2
name: SQLI-BASE-Func
type: SQLI
description: 检测特定命令执行函数
expr: ((?:merge.*?using\s*?\()|(execute\s*?immediate\s*?[\"'`])|(?:match\s*?[\w(),+-]+\s*?against\s*?\())
mode: match(urlDecode(header_uri|body_buf))
- id: 302014
level: 1
name: SQLI-BASE-Character
type: SQLI
description: 检测反引号、空格、注释等sql注入绕过行为
expr: ((?:,.*?[)\da-f\"'`][\"'`](?:[\"'`].*?[\"'`]|\Z|[^\"'`]+))|(?:\Wselect.+\W*?from)|((?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s*?\(\s*?space\s*?\())
mode: match(urlDecode(header_uri|body_buf))
- id: 302015
level: 1
name: SQLI-BASE-Usual1
type: SQLI
description: 检测mysql空格、条件及char注入行为
expr: ((?:\)\s*?when\s*?\d+\s*?then)|(?:\/\*!\s?\d+)|(?:ch(?:a)?r\s*?\(\s*?\d)|(?:(?:(n?and|x?x?or|div|like|between|and|not)\s+|\|\||\&\&)\s*?\w+\())
mode: match(urlDecode(header_uri|body_buf))
- id: 302016
level: 2
name: SQLI-BASE-Hex
type: SQLI
description: 检测到sql hex编码
expr: ((?:\A|[^\d])0x[a-f\d]{3,}[a-f\d]*)+
mode: match(urlDecode(header_uri|body_buf))
- id: 302017
level: 1
name: SQLI-BASE-Usual2
type: SQLI
description: 可能的注入尝试行为
expr: ((\'|\"){1,}.*(and|or).*(\+|\-|\=))
mode: match(urlDecode(header_uri|body_buf))
- id: 302018
level: 1
name: SQLI-BASE-Probe
type: SQLI
description: 普通SQL注入探测
expr: (?:\"\\s*or\\s*\"?\\d)|(?:\\\\x(?:23|27|3d))|(?:^.?\"$)|(?:(?:^[\"\\\\]*(?:[\\d\"]+|[^\"]+\"))+\\s*(?:n?and|x?or|not|\\|\\||\\&\\&)\\s*[\\w\"[+&!@(),.-])|(?:[^\\w\\s]\\w+\\s*[|-]\\s*\"\\s*\\w)|(?:@\\w+\\s+(and|or)\\s*[\"\\d]+)|(?:@[\\w-]+\\s(and|or)\\s*[^\\w\\s])|(?:[^\\w\\s:]\\s*\\d\\W+[^\\w\\s]\\s*\".)|(?:\\Winformation_schema|table_name\\W)
mode: match(urlDecode(header_uri|body_buf))
status: 0
- category_id: c_03
category:
en: XSS detection
zh: XSS 检测
description:
en: XSS flaws occur when new web pages for an application contain untrusted, improperly validated or escaped data, or when existing web pages are updated using browser APIs that can create HTML or JavaScript. XSS allows an attacker to execute script in a victim's browser and hijack user sessions, deface websites, or redirect users to malicious sites.
zh: 当应用程序的新网页中包含不受信任的、未经恰当验证或转义的数据,或者使用可以创建 HTML 或 JavaScript 的浏览器 API更新现有的网页时,会出现 XSS 缺陷。XSS 让攻击者能够在受害者的浏览器中执行脚本,并劫持用户会话、破坏网站或将用户重定向到恶意站点。
rules:
- id: 303001
level: 1
name: XSS-BASE-Script
type: XSS
description: script标签检测
expr: (?i)([<<]script[^>>]*[>>][\s\S]*?)
mode: match(urlDecode(header_uri|body_buf))
- id: 303002
level: 1
name: XSS-BASE-TagAction
type: XSS
description: 标签内事件检测
expr: (?i)([\s\"'`;\/0-9\=\x0B\x09\x0C\x3B\x2C\x28\x3B]+on[a-zA-Z]+[\s\x0B\x09\x0C\x3B\x2C\x28\x3B]*?=)
mode: match(urlDecode(header_uri|body_buf))
- id: 303003
level: 1
name: XSS-BASE-TagAttribute
type: XSS
description: 标签属性向量检测
expr: (?i)[\s\S](?:x(?:link:href|html|mlns)|!ENTITY.*?SYSTEM|data:text\/html|pattern(?=.*?=)|formaction|\@import|base64)\b
mode: match(urlDecode(header_uri|body_buf))
- id: 303004
level: 1
name: XSS-BASE-JsURI
type: XSS
description: Javascript URI向量检测
expr: (?i)(?:<(?:(?:apple|objec)t|isindex|embed|style|form|meta)\b[^>]*?>[\s\S]*?|(?:=|U\s*?R\s*?L\s*?\()\s*?[^>]*?\s*?S\s*?C\s*?R\s*?I\s*?P\s*?T\s*?:)
mode: match(urlDecode(header_uri|body_buf))
- id: 303005
level: 2
name: XSS-BASE-HtmlInjetion
type: XSS
description: 非Script Html注入类检查
expr: (?i)<[^\w<>]*(?:[^<>\"'\s]*:)?[^\w<>]*(?:\W*?s\W*?c\W*?r\W*?i\W*?p\W*?t|\W*?f\W*?o\W*?r\W*?m|\W*?s\W*?t\W*?y\W*?l\W*?e|\W*?s\W*?v\W*?g|\W*?m\W*?a\W*?r\W*?q\W*?u\W*?e\W*?e|(?:\W*?l\W*?i\W*?n\W*?k|\W*?o\W*?b\W*?j\W*?e\W*?c\W*?t|\W*?e\W*?m\W*?b\W*?e\W*?d|\W*?a\W*?p\W*?p\W*?l\W*?e\W*?t|\W*?p\W*?a\W*?r\W*?a\W*?m|\W*?i?\W*?f\W*?r\W*?a\W*?m\W*?e|\W*?b\W*?a\W*?s\W*?e|\W*?b\W*?o\W*?d\W*?y|\W*?m\W*?e\W*?t\W*?a|\W*?i\W*?m\W*?a?\W*?g\W*?e?|\W*?v\W*?i\W*?d\W*?e\W*?o|\W*?a\W*?u\W*?d\W*?i\W*?o|\W*?b\W*?i\W*?n\W*?d\W*?i\W*?n\W*?g\W*?s|\W*?s\W*?e\W*?t|\W*?a\W*?n\W*?i\W*?m\W*?a\W*?t\W*?e)[^>\w])|(?:<\w[\s\S]*[\s\/]|['\"](?:[\s\S]*[\s\/])?)(?:formaction|style|background|src|lowsrc|ping|on(?:d(?:e(?:vice(?:(?:orienta|mo)tion|proximity|found|light)|livery(?:success|error)|activate)|r(?:ag(?:e(?:n(?:ter|d)|xit)|(?:gestur|leav)e|start|drop|over)?|op)|i(?:s(?:c(?:hargingtimechange|onnect(?:ing|ed))|abled)|aling)|ata(?:setc(?:omplete|hanged)|(?:availabl|chang)e|error)|urationchange|ownloading|blclick)|Moz(?:M(?:agnifyGesture(?:Update|Start)?|ouse(?:PixelScroll|Hittest))|S(?:wipeGesture(?:Update|Start|End)?|crolledAreaChanged)|(?:(?:Press)?TapGestur|BeforeResiz)e|EdgeUI(?:C(?:omplet|ancel)|Start)ed|RotateGesture(?:Update|Start)?|A(?:udioAvailable|fterPaint))|c(?:o(?:m(?:p(?:osition(?:update|start|end)|lete)|mand(?:update)?)|n(?:t(?:rolselect|extmenu)|nect(?:ing|ed))|py)|a(?:(?:llschang|ch)ed|nplay(?:through)?|rdstatechange)|h(?:(?:arging(?:time)?ch)?ange|ecking)|(?:fstate|ell)change|u(?:echange|t)|l(?:ick|ose))|m(?:o(?:z(?:pointerlock(?:change|error)|(?:orientation|time)change|fullscreen(?:change|error)|network(?:down|up)load)|use(?:(?:lea|mo)ve|o(?:ver|ut)|enter|wheel|down|up)|ve(?:start|end)?)|essage|ark)|s(?:t(?:a(?:t(?:uschanged|echange)|lled|rt)|k(?:sessione|comma)nd|op)|e(?:ek(?:complete|ing|ed)|(?:lec(?:tstar)?)?t|n(?:ding|t))|u(?:ccess|spend|bmit)|peech(?:start|end)|ound(?:start|end)|croll|how)|b(?:e(?:for(?:e(?:(?:scriptexecu|activa)te|u(?:nload|pdate)|p(?:aste|rint)|c(?:opy|ut)|editfocus)|deactivate)|gin(?:Event)?)|oun(?:dary|ce)|l(?:ocked|ur)|roadcast|usy)|a(?:n(?:imation(?:iteration|start|end)|tennastatechange)|fter(?:(?:scriptexecu|upda)te|print)|udio(?:process|start|end)|d(?:apteradded|dtrack)|ctivate|lerting|bort)|DOM(?:Node(?:Inserted(?:IntoDocument)?|Removed(?:FromDocument)?)|(?:CharacterData|Subtree)Modified|A(?:ttrModified|ctivate)|Focus(?:Out|In)|MouseScroll)|r(?:e(?:s(?:u(?:m(?:ing|e)|lt)|ize|et)|adystatechange|pea(?:tEven)?t|movetrack|trieving|ceived)|ow(?:s(?:inserted|delete)|e(?:nter|xit))|atechange)|p(?:op(?:up(?:hid(?:den|ing)|show(?:ing|n))|state)|a(?:ge(?:hide|show)|(?:st|us)e|int)|ro(?:pertychange|gress)|lay(?:ing)?)|t(?:ouch(?:(?:lea|mo)ve|en(?:ter|d)|cancel|start)|ime(?:update|out)|ransitionend|ext)|u(?:s(?:erproximity|sdreceived)|p(?:gradeneeded|dateready)|n(?:derflow|load))|f(?:o(?:rm(?:change|input)|cus(?:out|in)?)|i(?:lterchange|nish)|ailed)|l(?:o(?:ad(?:e(?:d(?:meta)?data|nd)|start)?|secapture)|evelchange|y)|g(?:amepad(?:(?:dis)?connected|button(?:down|up)|axismove)|et)|e(?:n(?:d(?:Event|ed)?|abled|ter)|rror(?:update)?|mptied|xit)|i(?:cc(?:cardlockerror|infochange)|n(?:coming|valid|put))|o(?:(?:(?:ff|n)lin|bsolet)e|verflow(?:changed)?|pen)|SVG(?:(?:Unl|L)oad|Resize|Scroll|Abort|Error|Zoom)|h(?:e(?:adphoneschange|l[dp])|ashchange|olding)|v(?:o(?:lum|ic)e|ersion)change|w(?:a(?:it|rn)ing|heel)|key(?:press|down|up)|(?:AppComman|Loa)d|no(?:update|match)|Request|zoom))[\s\x08]*?=
mode: match(urlDecode(header_uri|body_buf))
- id: 303006
level: 1
name: XSS-BASE-AttributionInjetct
type: XSS
description: 非Script 属性类注入检查
expr: (?i)(?:\W|^)(?:javascript:(?:[\s\S]+[=\\\(\[\.<]|[\s\S]*?(?:\bname\b|\\[ux]\d))|data:(?:(?:[a-z]\w+\/\w[\w+-]+\w)?[;,]|[\s\S]*?;[\s\S]*?\b(?:base64|charset=)|[\s\S]*?,[\s\S]*?<[\s\S]*?\w[\s\S]*?>))|@\W*?i\W*?m\W*?p\W*?o\W*?r\W*?t\W*?(?:\/\*[\s\S]*?)?(?:[\"']|\W*?u\W*?r\W*?l[\s\S]*?\()|\W*?-\W*?m\W*?o\W*?z\W*?-\W*?b\W*?i\W*?n\W*?d\W*?i\W*?n\W*?g[\s\S]*?:[\s\S]*?\W*?u\W*?r\W*?l[\s\S]*?\(
mode: match(urlDecode(header_uri|body_buf))
- id: 303007
level: 1
name: XSS-BASE-BadAttribution
type: XSS
description: 禁止的Html属性
expr: (?i)\b(?:s(?:tyle|rc)|href)\b[\s\S]*?=
mode: match(urlDecode(header_uri|body_buf))
- id: 303008
level: 2
name: XSS-BASE-TAGCheck
type: XSS
description: HTML标签检查
expr: <(a|abbr|acronym|address|applet|area|audioscope|b|base|basefront|bdo|bgsound|big|blackface|blink|blockquote|body|bq|br|button|caption|center|cite|code|col|colgroup|comment|dd|del|dfn|dir|div|dl|dt|em|embed|fieldset|fn|font|form|frame|frameset|h1|head|hr|html|i|iframe|ilayer|img|input|ins|isindex|kdb|keygen|label|layer|legend|li|limittext|link|listing|map|marquee|menu|meta|multicol|nobr|noembed|noframes|noscript|nosmartquotes|object|ol|optgroup|option|p|param|plaintext|pre|q|rt|ruby|s|samp|script|select|server|shadow|sidebar|small|spacer|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|ul|var|wbr|xml|xmp)\W
mode: match(urlDecode(header_uri|body_buf))
- id: 303009
level: 3
name: XSS-BASE-IE1
type: XSS
description: IE的XSS过滤器规则1
expr: (?:<style.*?>.*?((@[i\\\\])|(([:=]|(&#x?0*((58)|(3A)|(61)|(3D));?)).*?([(\\\\]|(&#x?0*((40)|(28)|(92)|(5C));?)))))
mode: match(urlDecode(header_uri|body_buf))
- id: 303010
level: 2
name: XSS-BASE-IE2
type: XSS
description: IE的XSS过滤器规则2
expr: (?:<.*[:]?vmlframe.*?[\s/+]*?src[\s/+]*=)
mode: match(urlDecode(header_uri|body_buf))
- id: 303011
level: 3
name: XSS-BASE-IE3
type: XSS
description: IE的XSS过滤器规则3
expr: (?:<EMBED[\s/+].*?((src)|(type)).*?=)
mode: match(urlDecode(header_uri|body_buf))
- id: 303012
level: 2
name: XSS-BASE-IE4
type: XSS
description: IE的XSS过滤器规则4
expr: <[?]?import[\s\/+\S]*?implementation[\s\/+]*?=
mode: match(urlDecode(header_uri|body_buf))
- id: 303013
level: 3
name: XSS-BASE-IE5
type: XSS
description: IE的XSS过滤器规则5
expr: (?:<META[\s/+].*?http-equiv[\s/+]*=[\s/+]*[\"\'`]?(((c|(&#x?0*((67)|(43)|(99)|(63));?)))|((r|(&#x?0*((82)|(52)|(114)|(72));?)))|((s|(&#x?0*((83)|(53)|(115)|(73));?)))))
mode: match(urlDecode(header_uri|body_buf))
- id: 303014
level: 2
name: XSS-BASE-IE6
type: XSS
description: IE的XSS过滤器规则6
expr: (?:<META[\s/+].*?charset[\s/+]*=)
mode: match(urlDecode(header_uri|body_buf))
- id: 303015
level: 1
name: XSS-BASE-IE7
type: XSS
description: IE的XSS过滤器规则7
expr: (?:<LINK[\s/+].*?href[\s/+]*=)
mode: match(urlDecode(header_uri|body_buf))
- id: 303016
level: 1
name: XSS-BASE-IE8
type: XSS
description: IE的XSS过滤器规则8
expr: (?:<BASE[\s/+].*?href[\s/+]*=)
mode: match(urlDecode(header_uri|body_buf))
- id: 303017
level: 2
name: XSS-BASE-IE9
type: XSS
description: IE的XSS过滤器规则9
expr: (?:<OBJECT[\s\/ ].*?((type)|(codetype)|(classid)|(code)|(data))[\s\/ ]*=)
mode: match(urlDecode(header_uri|body_buf))
- id: 303018
level: 1
name: XSS-BASE-Probe
type: XSS
description: 常规xss攻击探测
expr: (?:,\\s*(?:alert|showmodaldialog|eval)\\s*,)|(?::\\s*eval\\s*[^\\s])|([^:\\s\\w,.\\\/?+-]\\s*)?(?<![a-z\\\/_@])(\\s*return\\s*)?(?:(?:document\\s*\\.)?(?:.+\\\/)?(?:alert|eval|msgbox|showmod(?:al|eless)dialog|showhelp|prompt|write(?:ln)?|confirm|dialog|open))\\s*(?:[^.a-z\\s\\-]|(?:\\s*[^\\s\\w,.@\\\/+-])|(?:java[\\s\\\/]*\\.[\\s\\\/]*lang)|(?:\\w\\s*=\\s*new\\s+\\w+)|(?:&\\s*\\w+\\s*\\)[^,])|(?:\\+[\\W\\d]*new\\s+\\w+[\\W\\d]*\\+)|(?:document\\.\\w)
mode: match(urlDecode(header_uri|body_buf))
status: 0
- category_id: c_01
category:
en: Command Injection Detection
zh: 命令注入检测
description:
en: A type of injection attack, including shell command injection, PHP code injection, Java code injection, etc. If the attacker successfully exploits it, it can cause the website to execute the code injected by the attacker.
zh: 注入攻击的一种,包含 shell 命令注入,PHP 代码注入,Java 代码注入等,若被攻击者成功利用,可导致网站执行攻击者注入的代码。
rules:
- id: 301001
level: 1
name: RCE_OS-BASE-1
type: RCE_OS
description: Linux命令注入检测1
expr: (?:;|\{|\||\|\||&|&&|\n|\r|\$\(|\$\(\(|`|\${|<\(|>\(|\(\s*\))\s*(?:{|\s*\(\s*|\w+=(?:[^\s]*|\$.*|\$.*|<.*|>.*|\'.*\'|\".*\")\s+|!\s*|\$)*\s*(?:'|\")*(?:[\?\*\[\]\(\)\-\|+\w'\"\./\\\\]+/)?[\\\\'\"]*(?:l[\\\\'\"]*(?:w[\\\\'\"]*p[\\\\'\"]*-[\\\\'\"]*(?:d[\\\\'\"]*(?:o[\\\\'\"]*w[\\\\'\"]*n[\\\\'\"]*l[\\\\'\"]*o[\\\\'\"]*a[\\\\'\"]*d|u[\\\\'\"]*m[\\\\'\"]*p)|r[\\\\'\"]*e[\\\\'\"]*q[\\\\'\"]*u[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*t|m[\\\\'\"]*i[\\\\'\"]*r[\\\\'\"]*r[\\\\'\"]*o[\\\\'\"]*r)|s(?:[\\\\'\"]*(?:b[\\\\'\"]*_[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*l[\\\\'\"]*e[\\\\'\"]*a[\\\\'\"]*s[\\\\'\"]*e|c[\\\\'\"]*p[\\\\'\"]*u|m[\\\\'\"]*o[\\\\'\"]*d|p[\\\\'\"]*c[\\\\'\"]*i|u[\\\\'\"]*s[\\\\'\"]*b|-[\\\\'\"]*F|h[\\\\'\"]*w|o[\\\\'\"]*f))?|z[\\\\'\"]*(?:(?:[ef][\\\\'\"]*)?g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|c[\\\\'\"]*(?:a[\\\\'\"]*t|m[\\\\'\"]*p)|m[\\\\'\"]*(?:o[\\\\'\"]*r[\\\\'\"]*e|a)|d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|l[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s)|e[\\\\'\"]*s[\\\\'\"]*s[\\\\'\"]*(?:(?:f[\\\\'\"]*i[\\\\'\"]*l|p[\\\\'\"]*i[\\\\'\"]*p)[\\\\'\"]*e|e[\\\\'\"]*c[\\\\'\"]*h[\\\\'\"]*o|(?:\s|<|>).*)|a[\\\\'\"]*s[\\\\'\"]*t[\\\\'\"]*(?:l[\\\\'\"]*o[\\\\'\"]*g(?:[\\\\'\"]*i[\\\\'\"]*n)?|c[\\\\'\"]*o[\\\\'\"]*m[\\\\'\"]*m|(?:\s|<|>).*)|o[\\\\'\"]*(?:c[\\\\'\"]*a[\\\\'\"]*(?:t[\\\\'\"]*e|l)[\\\\'\"]*(?:\s|<|>).*|g[\\\\'\"]*n[\\\\'\"]*a[\\\\'\"]*m[\\\\'\"]*e)|d[\\\\'\"]*(?:c[\\\\'\"]*o[\\\\'\"]*n[\\\\'\"]*f[\\\\'\"]*i[\\\\'\"]*g|d[\\\\'\"]*(?:\s|<|>).*)|f[\\\\'\"]*t[\\\\'\"]*p(?:[\\\\'\"]*g[\\\\'\"]*e[\\\\'\"]*t)?|(?:[np]|y[\\\\'\"]*n[\\\\'\"]*x)[\\\\'\"]*(?:\s|<|>).*)|b[\\\\'\"]*(?:z[\\\\'\"]*(?:(?:[ef][\\\\'\"]*)?g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|l[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|m[\\\\'\"]*o[\\\\'\"]*r[\\\\'\"]*e|c[\\\\'\"]*a[\\\\'\"]*t|i[\\\\'\"]*p[\\\\'\"]*2)|s[\\\\'\"]*d[\\\\'\"]*(?:c[\\\\'\"]*a[\\\\'\"]*t|i[\\\\'\"]*f[\\\\'\"]*f|t[\\\\'\"]*a[\\\\'\"]*r)|a[\\\\'\"]*(?:t[\\\\'\"]*c[\\\\'\"]*h[\\\\'\"]*(?:\s|<|>).*|s[\\\\'\"]*h)|r[\\\\'\"]*e[\\\\'\"]*a[\\\\'\"]*k[\\\\'\"]*s[\\\\'\"]*w|u[\\\\'\"]*i[\\\\'\"]*l[\\\\'\"]*t[\\\\'\"]*i[\\\\'\"]*n)|c[\\\\'\"]*(?:o[\\\\'\"]*(?:m[\\\\'\"]*(?:p[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|m[\\\\'\"]*a[\\\\'\"]*n[\\\\'\"]*d)[\\\\'\"]*(?:\s|<|>).*|p[\\\\'\"]*r[\\\\'\"]*o[\\\\'\"]*c)|h[\\\\'\"]*(?:d[\\\\'\"]*i[\\\\'\"]*r[\\\\'\"]*(?:\s|<|>).*|f[\\\\'\"]*l[\\\\'\"]*a[\\\\'\"]*g[\\\\'\"]*s|a[\\\\'\"]*t[\\\\'\"]*t[\\\\'\"]*r|m[\\\\'\"]*o[\\\\'\"]*d)|r[\\\\'\"]*o[\\\\'\"]*n[\\\\'\"]*t[\\\\'\"]*a[\\\\'\"]*b|(?:[cp]|a[\\\\'\"]*t)[\\\\'\"]*(?:\s|<|>).*|u[\\\\'\"]*r[\\\\'\"]*l|s[\\\\'\"]*h)|f[\\\\'\"]*(?:i(?:[\\\\'\"]*(?:l[\\\\'\"]*e[\\\\'\"]*(?:t[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*t|(?:\s|<|>).*)|n[\\\\'\"]*d[\\\\'\"]*(?:\s|<|>).*))?|t[\\\\'\"]*p[\\\\'\"]*(?:s[\\\\'\"]*t[\\\\'\"]*a[\\\\'\"]*t[\\\\'\"]*s|w[\\\\'\"]*h[\\\\'\"]*o|(?:\s|<|>).*)|u[\\\\'\"]*n[\\\\'\"]*c[\\\\'\"]*t[\\\\'\"]*i[\\\\'\"]*o[\\\\'\"]*n|(?:e[\\\\'\"]*t[\\\\'\"]*c[\\\\'\"]*h|c)[\\\\'\"]*(?:\s|<|>).*|o[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*h|g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p)|e[\\\\'\"]*(?:n[\\\\'\"]*(?:v(?:[\\\\'\"]*-[\\\\'\"]*u[\\\\'\"]*p[\\\\'\"]*d[\\\\'\"]*a[\\\\'\"]*t[\\\\'\"]*e)?|d[\\\\'\"]*(?:i[\\\\'\"]*f|s[\\\\'\"]*w))|x[\\\\'\"]*(?:p[\\\\'\"]*(?:a[\\\\'\"]*n[\\\\'\"]*d|o[\\\\'\"]*r[\\\\'\"]*t|r)|e[\\\\'\"]*c[\\\\'\"]*(?:\s|<|>).*|i[\\\\'\"]*t)|c[\\\\'\"]*h[\\\\'\"]*o[\\\\'\"]*(?:\s|<|>).*|g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|s[\\\\'\"]*a[\\\\'\"]*c|v[\\\\'\"]*a[\\\\'\"]*l)|h[\\\\'\"]*(?:t[\\\\'\"]*(?:d[\\\\'\"]*i[\\\\'\"]*g[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*t|p[\\\\'\"]*a[\\\\'\"]*s[\\\\'\"]*s[\\\\'\"]*w[\\\\'\"]*d)|o[\\\\'\"]*s[\\\\'\"]*t[\\\\'\"]*(?:n[\\\\'\"]*a[\\\\'\"]*m[\\\\'\"]*e|i[\\\\'\"]*d)|(?:e[\\\\'\"]*a[\\\\'\"]*d|u[\\\\'\"]*p)[\\\\'\"]*(?:\s|<|>).*|i[\\\\'\"]*s[\\\\'\"]*t[\\\\'\"]*o[\\\\'\"]*r[\\\\'\"]*y)|i[\\\\'\"]*(?:p[\\\\'\"]*(?:(?:6[\\\\'\"]*)?t[\\\\'\"]*a[\\\\'\"]*b[\\\\'\"]*l[\\\\'\"]*e[\\\\'\"]*s|c[\\\\'\"]*o[\\\\'\"]*n[\\\\'\"]*f[\\\\'\"]*i[\\\\'\"]*g)|r[\\\\'\"]*b(?:[\\\\'\"]*(?:1(?:[\\\\'\"]*[89])?|2[\\\\'\"]*[012]))?|f[\\\\'\"]*c[\\\\'\"]*o[\\\\'\"]*n[\\\\'\"]*f[\\\\'\"]*i[\\\\'\"]*g|d[\\\\'\"]*(?:\s|<|>).*)|g[\\\\'\"]*(?:(?:e[\\\\'\"]*t[\\\\'\"]*f[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*l|r[\\\\'\"]*e[\\\\'\"]*p|c[\\\\'\"]*c|i[\\\\'\"]*t)[\\\\'\"]*(?:\s|<|>).*|z[\\\\'\"]*(?:c[\\\\'\"]*a[\\\\'\"]*t|i[\\\\'\"]*p)|u[\\\\'\"]*n[\\\\'\"]*z[\\\\'\"]*i[\\\\'\"]*p|d[\\\\'\"]*b)|a[\\\\'\"]*(?:(?:l[\\\\'\"]*i[\\\\'\"]*a[\\\\'\"]*s|w[\\\\'\"]*k)[\\\\'\"]*(?:\s|<|>).*|d[\\\\'\"]*d[\\\\'\"]*u[\\\\'\"]*s[\\\\'\"]*e[\\\\'\"]*r|p[\\\\'\"]*t[\\\\'\"]*-[\\\\'\"]*g[\\\\'\"]*e[\\\\'\"]*t|r[\\\\'\"]*(?:c[\\\\'\"]*h[\\\\'\"]*(?:\s|<|>).*|p))|d[\\\\'\"]*(?:h[\\\\'\"]*c[\\\\'\"]*l[\\\\'\"]*i[\\\\'\"]*e[\\\\'\"]*n[\\\\'\"]*t|(?:i[\\\\'\"]*f[\\\\'\"]*f|u)[\\\\'\"]*(?:\s|<|>).*|(?:m[\\\\'\"]*e[\\\\'\"]*s|p[\\\\'\"]*k)[\\\\'\"]*g|o[\\\\'\"]*(?:a[\\\\'\"]*s|n[\\\\'\"]*e)|a[\\\\'\"]*s[\\\\'\"]*h)|m[\\\\'\"]*(?:(?:k[\\\\'\"]*d[\\\\'\"]*i[\\\\'\"]*r|o[\\\\'\"]*r[\\\\'\"]*e)[\\\\'\"]*(?:\s|<|>).*|a[\\\\'\"]*i[\\\\'\"]*l[\\\\'\"]*(?:x[\\\\'\"]*(?:\s|<|>).*|q)|l[\\\\'\"]*o[\\\\'\"]*c[\\\\'\"]*a[\\\\'\"]*t[\\\\'\"]*e)|j[\\\\'\"]*(?:(?:a[\\\\'\"]*v[\\\\'\"]*a|o[\\\\'\"]*b[\\\\'\"]*s)[\\\\'\"]*(?:\s|<|>).*|e[\\\\'\"]*x[\\\\'\"]*e[\\\\'\"]*c)|k[\\\\'\"]*i[\\\\'\"]*l[\\\\'\"]*l[\\\\'\"]*(?:a[\\\\'\"]*l[\\\\'\"]*l|(?:\s|<|>).*)|(?:G[\\\\'\"]*E[\\\\'\"]*T[\\\\'\"]*(?:\s|<|>)|\.\s).*|7[\\\\'\"]*z(?:[\\\\'\"]*[ar])?)\b
mode: match(urlDecode(header_uri|body_buf))
- id: 301002
level: 1
name: RCE_OS-BASE-2
type: RCE_OS
description: Linux命令注入检测2
expr: (?:;|\{|\||\|\||&|&&|\n|\r|\$\(|\$\(\(|`|\${|<\(|>\(|\(\s*\))\s*(?:{|\s*\(\s*|\w+=(?:[^\s]*|\$.*|\$.*|<.*|>.*|\'.*\'|\".*\")\s+|!\s*|\$)*\s*(?:'|\")*(?:[\?\*\[\]\(\)\-\|+\w'\"\./\\\\]+/)?[\\\\'\"]*(?:s[\\\\'\"]*(?:e[\\\\'\"]*(?:t[\\\\'\"]*(?:(?:f[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*l[\\\\'\"]*)?(?:\s|<|>).*|e[\\\\'\"]*n[\\\\'\"]*v|s[\\\\'\"]*i[\\\\'\"]*d)|n[\\\\'\"]*d[\\\\'\"]*m[\\\\'\"]*a[\\\\'\"]*i[\\\\'\"]*l|d[\\\\'\"]*(?:\s|<|>).*)|h[\\\\'\"]*(?:\.[\\\\'\"]*d[\\\\'\"]*i[\\\\'\"]*s[\\\\'\"]*t[\\\\'\"]*r[\\\\'\"]*i[\\\\'\"]*b|u[\\\\'\"]*t[\\\\'\"]*d[\\\\'\"]*o[\\\\'\"]*w[\\\\'\"]*n|(?:\s|<|>).*)|o[\\\\'\"]*(?:(?:u[\\\\'\"]*r[\\\\'\"]*c[\\\\'\"]*e|r[\\\\'\"]*t)[\\\\'\"]*(?:\s|<|>).*|c[\\\\'\"]*a[\\\\'\"]*t)|c[\\\\'\"]*(?:h[\\\\'\"]*e[\\\\'\"]*d|p[\\\\'\"]*(?:\s|<|>).*)|t[\\\\'\"]*r[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*g[\\\\'\"]*s|(?:l[\\\\'\"]*e[\\\\'\"]*e|f[\\\\'\"]*t)[\\\\'\"]*p|y[\\\\'\"]*s[\\\\'\"]*c[\\\\'\"]*t[\\\\'\"]*l|u[\\\\'\"]*(?:(?:\s|<|>).*|d[\\\\'\"]*o)|d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|s[\\\\'\"]*h|v[\\\\'\"]*n)|p[\\\\'\"]*(?:k[\\\\'\"]*(?:g(?:(?:[\\\\'\"]*_)?[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*f[\\\\'\"]*o)?|e[\\\\'\"]*x[\\\\'\"]*e[\\\\'\"]*c|i[\\\\'\"]*l[\\\\'\"]*l)|t[\\\\'\"]*a[\\\\'\"]*r(?:[\\\\'\"]*(?:d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p))?|a[\\\\'\"]*(?:t[\\\\'\"]*c[\\\\'\"]*h[\\\\'\"]*(?:\s|<|>).*|s[\\\\'\"]*s[\\\\'\"]*w[\\\\'\"]*d)|r[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*t[\\\\'\"]*(?:e[\\\\'\"]*n[\\\\'\"]*v|f[\\\\'\"]*(?:\s|<|>).*)|y[\\\\'\"]*t[\\\\'\"]*h[\\\\'\"]*o[\\\\'\"]*n(?:[\\\\'\"]*(?:3(?:[\\\\'\"]*m)?|2))?|e[\\\\'\"]*r[\\\\'\"]*(?:l(?:[\\\\'\"]*(?:s[\\\\'\"]*h|5))?|m[\\\\'\"]*s)|(?:g[\\\\'\"]*r[\\\\'\"]*e|f[\\\\'\"]*t)[\\\\'\"]*p|(?:u[\\\\'\"]*s[\\\\'\"]*h|o[\\\\'\"]*p)[\\\\'\"]*d|h[\\\\'\"]*p(?:[\\\\'\"]*[57])?|i[\\\\'\"]*n[\\\\'\"]*g|s[\\\\'\"]*(?:\s|<|>).*)|n[\\\\'\"]*(?:c[\\\\'\"]*(?:\.[\\\\'\"]*(?:t[\\\\'\"]*r[\\\\'\"]*a[\\\\'\"]*d[\\\\'\"]*i[\\\\'\"]*t[\\\\'\"]*i[\\\\'\"]*o[\\\\'\"]*n[\\\\'\"]*a[\\\\'\"]*l|o[\\\\'\"]*p[\\\\'\"]*e[\\\\'\"]*n[\\\\'\"]*b[\\\\'\"]*s[\\\\'\"]*d)|(?:\s|<|>).*|a[\\\\'\"]*t)|e[\\\\'\"]*t[\\\\'\"]*(?:k[\\\\'\"]*i[\\\\'\"]*t[\\\\'\"]*-[\\\\'\"]*f[\\\\'\"]*t[\\\\'\"]*p|(?:s[\\\\'\"]*t|c)[\\\\'\"]*a[\\\\'\"]*t|(?:\s|<|>).*)|s[\\\\'\"]*(?:l[\\\\'\"]*o[\\\\'\"]*o[\\\\'\"]*k[\\\\'\"]*u[\\\\'\"]*p|t[\\\\'\"]*a[\\\\'\"]*t)|(?:a[\\\\'\"]*n[\\\\'\"]*o|i[\\\\'\"]*c[\\\\'\"]*e)[\\\\'\"]*(?:\s|<|>).*|(?:o[\\\\'\"]*h[\\\\'\"]*u|m[\\\\'\"]*a)[\\\\'\"]*p|p[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*g)|r[\\\\'\"]*(?:e[\\\\'\"]*(?:(?:p[\\\\'\"]*(?:l[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*e|e[\\\\'\"]*a[\\\\'\"]*t)|n[\\\\'\"]*a[\\\\'\"]*m[\\\\'\"]*e)[\\\\'\"]*(?:\s|<|>).*|a[\\\\'\"]*l[\\\\'\"]*p[\\\\'\"]*a[\\\\'\"]*t[\\\\'\"]*h)|m[\\\\'\"]*(?:(?:d[\\\\'\"]*i[\\\\'\"]*r[\\\\'\"]*)?(?:\s|<|>).*|u[\\\\'\"]*s[\\\\'\"]*e[\\\\'\"]*r)|u[\\\\'\"]*b[\\\\'\"]*y(?:[\\\\'\"]*(?:1(?:[\\\\'\"]*[89])?|2[\\\\'\"]*[012]))?|(?:a[\\\\'\"]*r|c[\\\\'\"]*p|p[\\\\'\"]*m)[\\\\'\"]*(?:\s|<|>).*|n[\\\\'\"]*a[\\\\'\"]*n[\\\\'\"]*o|o[\\\\'\"]*u[\\\\'\"]*t[\\\\'\"]*e|s[\\\\'\"]*y[\\\\'\"]*n[\\\\'\"]*c)|t[\\\\'\"]*(?:c[\\\\'\"]*(?:p[\\\\'\"]*(?:t[\\\\'\"]*r[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*e[\\\\'\"]*r[\\\\'\"]*o[\\\\'\"]*u[\\\\'\"]*t[\\\\'\"]*e|i[\\\\'\"]*n[\\\\'\"]*g)|s[\\\\'\"]*h)|r[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*e[\\\\'\"]*r[\\\\'\"]*o[\\\\'\"]*u[\\\\'\"]*t[\\\\'\"]*e(?:[\\\\'\"]*6)?|e[\\\\'\"]*(?:l[\\\\'\"]*n[\\\\'\"]*e[\\\\'\"]*t|e[\\\\'\"]*(?:\s|<|>).*)|i[\\\\'\"]*m[\\\\'\"]*e[\\\\'\"]*(?:o[\\\\'\"]*u[\\\\'\"]*t|(?:\s|<|>).*)|a[\\\\'\"]*(?:i[\\\\'\"]*l(?:[\\\\'\"]*f)?|r[\\\\'\"]*(?:\s|<|>).*)|o[\\\\'\"]*(?:u[\\\\'\"]*c[\\\\'\"]*h[\\\\'\"]*(?:\s|<|>).*|p))|u[\\\\'\"]*(?:n[\\\\'\"]*(?:l[\\\\'\"]*(?:i[\\\\'\"]*n[\\\\'\"]*k[\\\\'\"]*(?:\s|<|>).*|z[\\\\'\"]*m[\\\\'\"]*a)|c[\\\\'\"]*o[\\\\'\"]*m[\\\\'\"]*p[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|a[\\\\'\"]*m[\\\\'\"]*e|r[\\\\'\"]*a[\\\\'\"]*r|s[\\\\'\"]*e[\\\\'\"]*t|z[\\\\'\"]*i[\\\\'\"]*p|x[\\\\'\"]*z)|s[\\\\'\"]*e[\\\\'\"]*r[\\\\'\"]*(?:(?:a[\\\\'\"]*d|m[\\\\'\"]*o)[\\\\'\"]*d|d[\\\\'\"]*e[\\\\'\"]*l)|l[\\\\'\"]*i[\\\\'\"]*m[\\\\'\"]*i[\\\\'\"]*t[\\\\'\"]*(?:\s|<|>).*)|m[\\\\'\"]*(?:y[\\\\'\"]*s[\\\\'\"]*q[\\\\'\"]*l(?:[\\\\'\"]*(?:d[\\\\'\"]*u[\\\\'\"]*m[\\\\'\"]*p(?:[\\\\'\"]*s[\\\\'\"]*l[\\\\'\"]*o[\\\\'\"]*w)?|h[\\\\'\"]*o[\\\\'\"]*t[\\\\'\"]*c[\\\\'\"]*o[\\\\'\"]*p[\\\\'\"]*y|a[\\\\'\"]*d[\\\\'\"]*m[\\\\'\"]*i[\\\\'\"]*n|s[\\\\'\"]*h[\\\\'\"]*o[\\\\'\"]*w))?|(?:(?:o[\\\\'\"]*u[\\\\'\"]*n|u[\\\\'\"]*t)[\\\\'\"]*t|v)[\\\\'\"]*(?:\s|<|>).*)|x[\\\\'\"]*(?:z[\\\\'\"]*(?:(?:[ef][\\\\'\"]*)?g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|d[\\\\'\"]*(?:i[\\\\'\"]*f[\\\\'\"]*f|e[\\\\'\"]*c)|c[\\\\'\"]*(?:a[\\\\'\"]*t|m[\\\\'\"]*p)|l[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|m[\\\\'\"]*o[\\\\'\"]*r[\\\\'\"]*e|(?:\s|<|>).*)|a[\\\\'\"]*r[\\\\'\"]*g[\\\\'\"]*s|t[\\\\'\"]*e[\\\\'\"]*r[\\\\'\"]*m|x[\\\\'\"]*d[\\\\'\"]*(?:\s|<|>).*)|z[\\\\'\"]*(?:(?:[ef][\\\\'\"]*)?g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|c[\\\\'\"]*(?:a[\\\\'\"]*t|m[\\\\'\"]*p)|d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|i[\\\\'\"]*p[\\\\'\"]*(?:\s|<|>).*|l[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|m[\\\\'\"]*o[\\\\'\"]*r[\\\\'\"]*e|r[\\\\'\"]*u[\\\\'\"]*n|s[\\\\'\"]*h)|o[\\\\'\"]*(?:p[\\\\'\"]*e[\\\\'\"]*n[\\\\'\"]*s[\\\\'\"]*s[\\\\'\"]*l|n[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*t[\\\\'\"]*r)|w[\\\\'\"]*(?:h[\\\\'\"]*o[\\\\'\"]*(?:a[\\\\'\"]*m[\\\\'\"]*i|(?:\s|<|>).*)|g[\\\\'\"]*e[\\\\'\"]*t|3[\\\\'\"]*m)|v[\\\\'\"]*i[\\\\'\"]*(?:m[\\\\'\"]*(?:\s|<|>).*|g[\\\\'\"]*r|p[\\\\'\"]*w)|y[\\\\'\"]*u[\\\\'\"]*m)\b
mode: match(urlDecode(header_uri|body_buf))
- id: 301003
level: 1
name: RCE_OS-BASE-3
type: RCE_OS
description: Linux命令注入检测3
expr: (?:^|=)\s*(?:{|\s*\(\s*|\w+=(?:[^\s]*|\$.*|\$.*|<.*|>.*|\'.*\'|\".*\")\s+|!\s*|\$)*\s*(?:'|\")*(?:[\?\*\[\]\(\)\-\|+\w'\"\./\\\\]+/)?[\\\\'\"]*(?:l[\\\\'\"]*(?:s(?:[\\\\'\"]*(?:b[\\\\'\"]*_[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*l[\\\\'\"]*e[\\\\'\"]*a[\\\\'\"]*s[\\\\'\"]*e|c[\\\\'\"]*p[\\\\'\"]*u|m[\\\\'\"]*o[\\\\'\"]*d|p[\\\\'\"]*c[\\\\'\"]*i|u[\\\\'\"]*s[\\\\'\"]*b|-[\\\\'\"]*F|o[\\\\'\"]*f))?|z[\\\\'\"]*(?:(?:[ef][\\\\'\"]*)?g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|c[\\\\'\"]*(?:a[\\\\'\"]*t|m[\\\\'\"]*p)|m[\\\\'\"]*(?:o[\\\\'\"]*r[\\\\'\"]*e|a)|d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|l[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s)|e[\\\\'\"]*s[\\\\'\"]*s[\\\\'\"]*(?:(?:f[\\\\'\"]*i[\\\\'\"]*l|p[\\\\'\"]*i[\\\\'\"]*p)[\\\\'\"]*e|e[\\\\'\"]*c[\\\\'\"]*h[\\\\'\"]*o)|a[\\\\'\"]*s[\\\\'\"]*t[\\\\'\"]*(?:l[\\\\'\"]*o[\\\\'\"]*g(?:[\\\\'\"]*i[\\\\'\"]*n)?|c[\\\\'\"]*o[\\\\'\"]*m[\\\\'\"]*m)|w[\\\\'\"]*p(?:[\\\\'\"]*-[\\\\'\"]*d[\\\\'\"]*o[\\\\'\"]*w[\\\\'\"]*n[\\\\'\"]*l[\\\\'\"]*o[\\\\'\"]*a[\\\\'\"]*d)?|f[\\\\'\"]*t[\\\\'\"]*p(?:[\\\\'\"]*g[\\\\'\"]*e[\\\\'\"]*t)?|y[\\\\'\"]*n[\\\\'\"]*x)|s[\\\\'\"]*(?:e[\\\\'\"]*(?:t[\\\\'\"]*(?:e[\\\\'\"]*n[\\\\'\"]*v|s[\\\\'\"]*i[\\\\'\"]*d)|n[\\\\'\"]*d[\\\\'\"]*m[\\\\'\"]*a[\\\\'\"]*i[\\\\'\"]*l|d)|h(?:[\\\\'\"]*\.[\\\\'\"]*d[\\\\'\"]*i[\\\\'\"]*s[\\\\'\"]*t[\\\\'\"]*r[\\\\'\"]*i[\\\\'\"]*b)?|o[\\\\'\"]*(?:u[\\\\'\"]*r[\\\\'\"]*c[\\\\'\"]*e|c[\\\\'\"]*a[\\\\'\"]*t)|t[\\\\'\"]*r[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*g[\\\\'\"]*s|y[\\\\'\"]*s[\\\\'\"]*c[\\\\'\"]*t[\\\\'\"]*l|c[\\\\'\"]*(?:h[\\\\'\"]*e[\\\\'\"]*d|p)|d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|f[\\\\'\"]*t[\\\\'\"]*p|u[\\\\'\"]*d[\\\\'\"]*o|s[\\\\'\"]*h|v[\\\\'\"]*n)|p[\\\\'\"]*(?:t[\\\\'\"]*a[\\\\'\"]*r(?:[\\\\'\"]*(?:d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p))?|y[\\\\'\"]*t[\\\\'\"]*h[\\\\'\"]*o[\\\\'\"]*n(?:[\\\\'\"]*(?:3(?:[\\\\'\"]*m)?|2))?|k[\\\\'\"]*(?:e[\\\\'\"]*x[\\\\'\"]*e[\\\\'\"]*c|i[\\\\'\"]*l[\\\\'\"]*l)|r[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*t[\\\\'\"]*e[\\\\'\"]*n[\\\\'\"]*v|(?:g[\\\\'\"]*r[\\\\'\"]*e|f[\\\\'\"]*t)[\\\\'\"]*p|e[\\\\'\"]*r[\\\\'\"]*l(?:[\\\\'\"]*5)?|h[\\\\'\"]*p(?:[\\\\'\"]*[57])?|i[\\\\'\"]*n[\\\\'\"]*g)|n[\\\\'\"]*(?:c(?:[\\\\'\"]*(?:\.[\\\\'\"]*(?:t[\\\\'\"]*r[\\\\'\"]*a[\\\\'\"]*d[\\\\'\"]*i[\\\\'\"]*t[\\\\'\"]*i[\\\\'\"]*o[\\\\'\"]*n[\\\\'\"]*a[\\\\'\"]*l|o[\\\\'\"]*p[\\\\'\"]*e[\\\\'\"]*n[\\\\'\"]*b[\\\\'\"]*s[\\\\'\"]*d)|a[\\\\'\"]*t))?|e[\\\\'\"]*t[\\\\'\"]*(?:k[\\\\'\"]*i[\\\\'\"]*t[\\\\'\"]*-[\\\\'\"]*f[\\\\'\"]*t[\\\\'\"]*p|(?:s[\\\\'\"]*t|c)[\\\\'\"]*a[\\\\'\"]*t)|o[\\\\'\"]*h[\\\\'\"]*u[\\\\'\"]*p|p[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*g|s[\\\\'\"]*t[\\\\'\"]*a[\\\\'\"]*t)|t[\\\\'\"]*(?:c[\\\\'\"]*(?:p[\\\\'\"]*(?:t[\\\\'\"]*r[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*e[\\\\'\"]*r[\\\\'\"]*o[\\\\'\"]*u[\\\\'\"]*t[\\\\'\"]*e|i[\\\\'\"]*n[\\\\'\"]*g)|s[\\\\'\"]*h)|r[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*e[\\\\'\"]*r[\\\\'\"]*o[\\\\'\"]*u[\\\\'\"]*t[\\\\'\"]*e(?:[\\\\'\"]*6)?|i[\\\\'\"]*m[\\\\'\"]*e(?:[\\\\'\"]*o[\\\\'\"]*u[\\\\'\"]*t)?|a[\\\\'\"]*(?:i[\\\\'\"]*l(?:[\\\\'\"]*f)?|r)|e[\\\\'\"]*l[\\\\'\"]*n[\\\\'\"]*e[\\\\'\"]*t)|r[\\\\'\"]*(?:e[\\\\'\"]*(?:p[\\\\'\"]*(?:l[\\\\'\"]*a[\\\\'\"]*c[\\\\'\"]*e|e[\\\\'\"]*a[\\\\'\"]*t)|a[\\\\'\"]*l[\\\\'\"]*p[\\\\'\"]*a[\\\\'\"]*t[\\\\'\"]*h|n[\\\\'\"]*a[\\\\'\"]*m[\\\\'\"]*e)|u[\\\\'\"]*b[\\\\'\"]*y(?:[\\\\'\"]*(?:1(?:[\\\\'\"]*[89])?|2[\\\\'\"]*[012]))?|m[\\\\'\"]*(?:u[\\\\'\"]*s[\\\\'\"]*e|d[\\\\'\"]*i)[\\\\'\"]*r|n[\\\\'\"]*a[\\\\'\"]*n[\\\\'\"]*o|s[\\\\'\"]*y[\\\\'\"]*n[\\\\'\"]*c|c[\\\\'\"]*p)|b[\\\\'\"]*(?:z[\\\\'\"]*(?:(?:[ef][\\\\'\"]*)?g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|l[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|m[\\\\'\"]*o[\\\\'\"]*r[\\\\'\"]*e|c[\\\\'\"]*a[\\\\'\"]*t)|s[\\\\'\"]*d[\\\\'\"]*(?:c[\\\\'\"]*a[\\\\'\"]*t|i[\\\\'\"]*f[\\\\'\"]*f|t[\\\\'\"]*a[\\\\'\"]*r)|u[\\\\'\"]*i[\\\\'\"]*l[\\\\'\"]*t[\\\\'\"]*i[\\\\'\"]*n|a[\\\\'\"]*s[\\\\'\"]*h)|m[\\\\'\"]*(?:y[\\\\'\"]*s[\\\\'\"]*q[\\\\'\"]*l[\\\\'\"]*(?:d[\\\\'\"]*u[\\\\'\"]*m[\\\\'\"]*p(?:[\\\\'\"]*s[\\\\'\"]*l[\\\\'\"]*o[\\\\'\"]*w)?|h[\\\\'\"]*o[\\\\'\"]*t[\\\\'\"]*c[\\\\'\"]*o[\\\\'\"]*p[\\\\'\"]*y|a[\\\\'\"]*d[\\\\'\"]*m[\\\\'\"]*i[\\\\'\"]*n|s[\\\\'\"]*h[\\\\'\"]*o[\\\\'\"]*w)|l[\\\\'\"]*o[\\\\'\"]*c[\\\\'\"]*a[\\\\'\"]*t[\\\\'\"]*e|a[\\\\'\"]*i[\\\\'\"]*l[\\\\'\"]*q)|u[\\\\'\"]*(?:n[\\\\'\"]*(?:c[\\\\'\"]*o[\\\\'\"]*m[\\\\'\"]*p[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|l[\\\\'\"]*z[\\\\'\"]*m[\\\\'\"]*a|a[\\\\'\"]*m[\\\\'\"]*e|r[\\\\'\"]*a[\\\\'\"]*r|s[\\\\'\"]*e[\\\\'\"]*t|z[\\\\'\"]*i[\\\\'\"]*p|x[\\\\'\"]*z)|s[\\\\'\"]*e[\\\\'\"]*r[\\\\'\"]*(?:(?:a[\\\\'\"]*d|m[\\\\'\"]*o)[\\\\'\"]*d|d[\\\\'\"]*e[\\\\'\"]*l))|x[\\\\'\"]*(?:z(?:[\\\\'\"]*(?:(?:[ef][\\\\'\"]*)?g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|d[\\\\'\"]*(?:i[\\\\'\"]*f[\\\\'\"]*f|e[\\\\'\"]*c)|c[\\\\'\"]*(?:a[\\\\'\"]*t|m[\\\\'\"]*p)|l[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|m[\\\\'\"]*o[\\\\'\"]*r[\\\\'\"]*e))?|a[\\\\'\"]*r[\\\\'\"]*g[\\\\'\"]*s)|z[\\\\'\"]*(?:(?:(?:[ef][\\\\'\"]*)?g[\\\\'\"]*r[\\\\'\"]*e|i)[\\\\'\"]*p|c[\\\\'\"]*(?:a[\\\\'\"]*t|m[\\\\'\"]*p)|d[\\\\'\"]*i[\\\\'\"]*f[\\\\'\"]*f|l[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*s|m[\\\\'\"]*o[\\\\'\"]*r[\\\\'\"]*e|r[\\\\'\"]*u[\\\\'\"]*n|s[\\\\'\"]*h)|f[\\\\'\"]*(?:t[\\\\'\"]*p[\\\\'\"]*(?:s[\\\\'\"]*t[\\\\'\"]*a[\\\\'\"]*t[\\\\'\"]*s|w[\\\\'\"]*h[\\\\'\"]*o)|i[\\\\'\"]*l[\\\\'\"]*e[\\\\'\"]*t[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*t|e[\\\\'\"]*t[\\\\'\"]*c[\\\\'\"]*h|g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p)|c[\\\\'\"]*(?:o[\\\\'\"]*(?:m[\\\\'\"]*m[\\\\'\"]*a[\\\\'\"]*n[\\\\'\"]*d|p[\\\\'\"]*r[\\\\'\"]*o[\\\\'\"]*c)|u[\\\\'\"]*r[\\\\'\"]*l|s[\\\\'\"]*h|c)|e[\\\\'\"]*(?:g[\\\\'\"]*r[\\\\'\"]*e[\\\\'\"]*p|c[\\\\'\"]*h[\\\\'\"]*o|v[\\\\'\"]*a[\\\\'\"]*l|x[\\\\'\"]*e[\\\\'\"]*c|n[\\\\'\"]*v)|d[\\\\'\"]*(?:m[\\\\'\"]*e[\\\\'\"]*s[\\\\'\"]*g|a[\\\\'\"]*s[\\\\'\"]*h|i[\\\\'\"]*f[\\\\'\"]*f|o[\\\\'\"]*a[\\\\'\"]*s)|g[\\\\'\"]*(?:z[\\\\'\"]*(?:c[\\\\'\"]*a[\\\\'\"]*t|i[\\\\'\"]*p)|r[\\\\'\"]*e[\\\\'\"]*p|c[\\\\'\"]*c)|w[\\\\'\"]*(?:h[\\\\'\"]*o[\\\\'\"]*a[\\\\'\"]*m[\\\\'\"]*i|g[\\\\'\"]*e[\\\\'\"]*t|3[\\\\'\"]*m)|j[\\\\'\"]*(?:o[\\\\'\"]*b[\\\\'\"]*s[\\\\'\"]*\s[\\\\'\"]*-[\\\\'\"]*x|a[\\\\'\"]*v[\\\\'\"]*a)|i[\\\\'\"]*r[\\\\'\"]*b(?:[\\\\'\"]*(?:1(?:[\\\\'\"]*[89])?|2[\\\\'\"]*[012]))?|o[\\\\'\"]*n[\\\\'\"]*i[\\\\'\"]*n[\\\\'\"]*t[\\\\'\"]*r|h[\\\\'\"]*(?:e[\\\\'\"]*a[\\\\'\"]*d|u[\\\\'\"]*p)|v[\\\\'\"]*i[\\\\'\"]*(?:g[\\\\'\"]*r|p[\\\\'\"]*w)|G[\\\\'\"]*E[\\\\'\"]*T)[\\\\'\"]*(?:\s|;|\||&|<|>)
mode: match(urlDecode(header_uri|body_buf))
status: 0
- category_id: c_05
category:
en: path crossing detection
zh: 路径穿越检测
description:
en: An attacker could exploit this vulnerability to gain access to unauthorized files or directories, possibly resulting in the disclosure of sensitive information or the execution of arbitrary code.
zh: 攻击者可以利用此漏洞访问未授权的文件或目录,可能导致敏感信息泄露或执行任意代码。
rules:
- id: 305001
level: 1
name: DT-BASE-UsualDT
type: DT
description: 常规路径穿越检测
expr: (?i)(?:\x5c|(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5c)|0x(?:2f|5c)|\/))(?:%(?:(?:f(?:(?:c%80|8)%8)?0%8|e)0%80%ae|2(?:(?:5(?:c0%25a|2))?e|%45)|u(?:(?:002|ff0)e|2024)|%32(?:%(?:%6|4)5|E)|c0(?:%[256aef]e|\.))|\.(?:%0[01]|\?)?|\?\.?|0x2e){2}(?:\x5c|(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5c)|0x(?:2f|5c)|\/))
mode: match(urlDecode(header_uri|body_buf))
- id: 305002
level: 1
name: DT-BASE-SpecialPath
type: DT
description: 特殊路径包含检测
expr: (?:%c0%ae\/)|(?:(?:\/|\\)(home|conf|usr|etc|proc|opt|s?bin|local|dev|tmp|kern|[br]oot|sys|system|windows|winnt|program|%[a-z_-]{3,}%)(?:\/|\\))|(?:(?:\/|\\)inetpub|localstart\.asp|boot\.ini)
mode: match(urlDecode(header_uri|body_buf))
- id: 305003
level: 3
name: DT-BASE-1
type: DT
description: 常规本地文件包含
expr: (?:^|[\\/])\.\.(?:[\\/]|$)
mode: match(urlDecode(header_uri|body_buf))
status: 0
- category_id: c_08
category:
en: PHP Code Injection Detection
zh: PHP 代码注入检测
description:
en: Allow attackers to execute malicious PHP system commands, endangering server security.
zh: 允许攻击者执行恶意的PHP系统命令,危及服务器安全。
rules:
- id: 308001
level: 1
name: RCE_PHP-BASE-PHPTag
type: RCE_PHP
description: 发现PHP标签
expr: (?:<\?php|\[(?:/|\\\\)?php\]|<script.*language=('|\"){0,1}php)
mode: match(urlDecode(header_uri|body_buf))
- id: 308002
level: 2
name: RCE_PHP-BASE-PHPProtocol
type: RCE_PHP
description: PHP协议文件读写流
expr: (?i)php://(std(in|out|err)|(in|out)put|fd|memory|temp|filter)
mode: match(urlDecode(header_uri|body_buf))
- id: 308003
level: 2
name: RCE_PHP-BASE-RiskFunc
type: RCE_PHP
description: 发现PHP危险函数
expr: (?i)\b(?:s(?:e(?:t(?:_(?:e(?:xception|rror)_handler|magic_quotes_runtime|include_path)|defaultstub)|ssion_s(?:et_save_handler|tart))|qlite_(?:(?:(?:unbuffered|single|array)_)?query|create_(?:aggregate|function)|p?open|exec)|tr(?:eam_(?:context_create|socket_client)|ipc?slashes|rev)|implexml_load_(?:string|file)|ocket_c(?:onnect|reate)|h(?:ow_sourc|a1_fil)e|pl_autoload_register|ystem)|p(?:r(?:eg_(?:replace(?:_callback(?:_array)?)?|match(?:_all)?|split)|oc_(?:(?:terminat|clos|nic)e|get_status|open)|int_r)|o(?:six_(?:get(?:(?:e[gu]|g)id|login|pwnam)|mk(?:fifo|nod)|ttyname|kill)|pen)|hp(?:_(?:strip_whitespac|unam)e|version|info)|g_(?:(?:execut|prepar)e|connect|query)|a(?:rse_(?:ini_file|str)|ssthru)|utenv)|r(?:unkit_(?:function_(?:re(?:defin|nam)e|copy|add)|method_(?:re(?:defin|nam)e|copy|add)|constant_(?:redefine|add))|e(?:(?:gister_(?:shutdown|tick)|name)_function|ad(?:(?:gz)?file|_exif_data|dir))|awurl(?:de|en)code)|i(?:mage(?:createfrom(?:(?:jpe|pn)g|x[bp]m|wbmp|gif)|(?:jpe|pn)g|g(?:d2?|if)|2?wbmp|xbm)|s_(?:(?:(?:execut|write?|read)ab|fi)le|dir)|ni_(?:get(?:_all)?|set)|terator_apply|ptcembed)|g(?:et(?:_(?:c(?:urrent_use|fg_va)r|meta_tags)|my(?:[gpu]id|inode)|(?:lastmo|cw)d|imagesize|env)|z(?:(?:(?:defla|wri)t|encod|fil)e|compress|open|read)|lob)|a(?:rray_(?:u(?:intersect(?:_u?assoc)?|diff(?:_u?assoc)?)|intersect_u(?:assoc|key)|diff_u(?:assoc|key)|filter|reduce|map)|ssert(?:_options)?)|h(?:tml(?:specialchars(?:_decode)?|_entity_decode|entities)|(?:ash(?:_(?:update|hmac))?|ighlight)_file|e(?:ader_register_callback|x2bin))|f(?:i(?:le(?:(?:[acm]tim|inod)e|(?:_exist|perm)s|group)?|nfo_open)|tp_(?:nb_(?:ge|pu)|connec|ge|pu)t|(?:unction_exis|pu)ts|write|open)|o(?:b_(?:get_(?:c(?:ontents|lean)|flush)|end_(?:clean|flush)|clean|flush|start)|dbc_(?:result(?:_all)?|exec(?:ute)?|connect)|pendir)|m(?:b_(?:ereg(?:_(?:replace(?:_callback)?|match)|i(?:_replace)?)?|parse_str)|(?:ove_uploaded|d5)_file|ethod_exists|ysql_query|kdir)|e(?:x(?:if_(?:t(?:humbnail|agname)|imagetype|read_data)|ec)|scapeshell(?:arg|cmd)|rror_reporting|val)|c(?:url_(?:file_create|exec|init)|onvert_uuencode|reate_function|hr)|u(?:n(?:serialize|pack)|rl(?:de|en)code|[ak]?sort)|(?:json_(?:de|en)cod|debug_backtrac|tmpfil)e|b(?:(?:son_(?:de|en)|ase64_en)code|zopen)|var_dump)(?:\s|/\*.*\*/|//.*|#.*)*\(.*\)
mode: match(urlDecode(header_uri|body_buf))
- id: 308004
level: 3
name: RCE_PHP-BASE-Serialized
type: RCE_PHP
description: PHP序列化注入
expr: \:\d+:{\w:\d+.*}$
mode: match(urlDecode(header_uri|body_buf))
- id: 308005
level: 3
name: RCE_PHP-BASE-VariableFunc
type: RCE_PHP
description: PHP变量函数调用
expr: \$+(?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*|\s*{.+})|(?:\s|\[.+\]|{.+}|/\*.*\*/|//.*|#.*)*\(.*\)
mode: match(urlDecode(header_uri|body_buf))
- id: 308006
level: 3
name: RCE_PHP-BASE-LowRiskFunc
type: RCE_PHP
description: 低风险PHP函数发现
expr: (?i)\b(?:i(?:s(?:_(?:in(?:t(?:eger)?|finite)|n(?:u(?:meric|ll)|an)|(?:calla|dou)ble|s(?:calar|tring)|f(?:inite|loat)|re(?:source|al)|l(?:ink|ong)|a(?:rray)?|object|bool)|set)|n(?:(?:clud|vok)e|t(?:div|val))|(?:mplod|dat)e|conv)|s(?:t(?:r(?:(?:le|sp)n|coll)|at)|(?:e(?:rializ|ttyp)|huffl)e|i(?:milar_text|zeof|nh?)|p(?:liti?|rintf)|(?:candi|ubst)r|y(?:mlink|slog)|o(?:undex|rt)|leep|rand|qrt)|f(?:ile(?:(?:siz|typ)e|owner|pro)|l(?:o(?:atval|ck|or)|ush)|(?:rea|mo)d|t(?:ell|ok)|unction|close|gets|stat|eof)|c(?:h(?:o(?:wn|p)|eckdate|root|dir|mod)|o(?:(?:(?:nsta|u)n|mpac)t|sh?|py)|lose(?:dir|log)|(?:urren|ryp)t|eil)|e(?:x(?:(?:trac|i)t|p(?:lode)?)|a(?:ster_da(?:te|ys)|ch)|r(?:ror_log|egi?)|mpty|cho|nd)|l(?:o(?:g(?:1[0p])?|caltime)|i(?:nk(?:info)?|st)|(?:cfirs|sta)t|evenshtein|trim)|d(?:i(?:(?:skfreespac)?e|r(?:name)?)|e(?:fined?|coct)|(?:oubleva)?l|ate)|r(?:e(?:(?:quir|cod|nam)e|adlin[ek]|wind|set)|an(?:ge|d)|ound|sort|trim)|m(?:b(?:split|ereg)|i(?:crotime|n)|a(?:i[ln]|x)|etaphone|y?sql|hash)|u(?:n(?:(?:tain|se)t|iqid|link)|s(?:leep|ort)|cfirst|mask)|a(?:s(?:(?:se|o)rt|inh?)|r(?:sort|ray)|tan[2h]?|cosh?|bs)|t(?:e(?:xtdomain|mpnam)|a(?:int|nh?)|ouch|ime|rim)|h(?:e(?:ader(?:s_(?:lis|sen)t)?|brev)|ypot|ash)|p(?:a(?:thinfo|ck)|r(?:intf?|ev)|close|o[sw]|i)|g(?:et(?:t(?:ext|ype)|date)|mdate)|o(?:penlog|ctdec|rd)|b(?:asename|indec)|n(?:atsor|ex)t|k(?:sort|ey)|quotemeta|wordwrap|virtual|join)(?:\s|/\*.*\*/|//.*|#.*)*\(.*\)
mode: match(urlDecode(header_uri|body_buf))
status: 0
- category_id: c_09
category:
en: JAVA code injection detection
zh: JAVA 代码注入检测
description:
en: Allow attackers to execute malicious JAVA system commands, endangering server security.
zh: 允许攻击者执行恶意的JAVA系统命令,危及服务器安全。
rules:
- id: 309001
level: 1
name: RCE_JAVA-BASE-Struts2RCE
type: RCE_JAVA
description: 常见的struts2命令注入攻击行为
expr: (%|#){0,}.*(\[|\{|\().*(@ognl.OgnlContext|java.lang.Runtime@getRuntime|java.io.BufferedReader|java.lang.ProcessBuilder)
mode: match(urlDecode(header_uri|body_buf))
- id: 309002
level: 1
name: RCE_JAVA-BASE-JavaFunc
type: RCE_JAVA
description: 敏感java函数调用
expr: java\.lang\.(?:runtime|processbuilder|invoke|getInputStream|boolean)
mode: match(urlDecode(header_uri|body_buf))
- id: 309003
level: 2
name: RCE_JAVA-BASE-CVE-2017-9805
type: RCE_JAVA
description: 针对CVE-2017-9805的检测规则
expr: (?:runtime|processbuilder)
mode: match(urlDecode(header_uri|body_buf))
- id: 309004
level: 2
name: RCE_JAVA-BASE-Sensitive
type: RCE_JAVA
description: java敏感函数调用检测
expr: (?:runtime|processbuilder)
mode: match(urlDecode(header_uri|body_buf))
status: 0
- category_id: c_14
category:
en: File upload detection
zh: 文件上传检测
description:
en: When the uploaded file is disguised as a malicious script with a normal suffix, the attacker can use the local file inclusion vulnerability to execute the file.
zh: 当上传文件伪装成正常后缀的恶意脚本时,攻击者可借助本地文件包含漏洞执行该文件。
rules:
- id: 314001
level: 2
name: UFL-BASE-1
type: UFL
description: 未授权文件上传1
expr: (.*\.(php|php5|jsp|jspx|asp|aspx|asa))
mode: match(urlDecode(body_para['filename']))
- id: 314002
level: 2
name: UFL-BASE-2
type: UFL
description: 未授权文件上传2
expr: (Content-Type:.*application/.*)
mode: match(urlDecode(substr(body_buf,0,1024)))
- id: 314003
level: 2
name: UFL-PHP-Webshell
type: UFL
description: 疑似PHP webshell文件上传
expr: (<\?php.*)
mode: match(urlDecode(substr(body_buf,0,2028)))
status: 0
- category_id: c_11
category:
en: Remote file inclusion detection
zh: 远程文件包含检测
description:
en: Attackers read or execute unauthorized files, which may lead to disclosure of sensitive information or execute the file with the help of file inclusion vulnerabilities.
zh: 攻击者读取或执行未授权的文件,可能导致敏感信息泄露或借助文件包含漏洞执行该文件。
rules:
- id: 311001
level: 1
name: RFI-BASE-IncludeIP
type: RFI
description: 远程文件包含协议中发现ip
expr: (file|ftp?|ftps?|https?):\/\/(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
mode: match(iterator(urlDecode(header_para|body_buf)))
- id: 311002
level: 2
name: RFI-BASE-IncludePara
type: RFI
description: 远程文件包含URL结尾中发现?
expr: (file|ftp?|ftps?|https?).*?\?+
mode: match(iterator(urlDecode(header_para|body_buf)))
- id: 311003
level: 3
name: RFI-BASE-Usual1
type: RFI
description: 远程文件包含检测1
expr: (file|ftp?|ftps?|https?)://([^/]*).*
mode: match(iterator(urlDecode(header_para|body_buf)))
status: 0
- category_id: c_06
category:
en: Sensitive Information Leakage Detection
zh: 敏感信息泄露检测
description:
en: Information such as source code and configuration files may be leaked to endanger system security.
zh: 可能泄露源码、配置文件等信息危害系统安全。
rules:
- id: 306001
level: 1
name: DL-BASE-BadSuffixes
type: DL
description: 危险后缀文件
expr: (\\|\/).*(.sql|.db|.war|.conf|.bak|.mdb|.properties|.ds_store)$
mode: match(urlDecode(header_uri))
- id: 306002
level: 1
name: DL-BASE-BadPath
type: DL
description: 危险文件路径
expr: (/WEB-INF/.*\.xml)|(/.svn/.*)|(/.git/.*)
mode: match(urlDecode(header_path))
- id: 306003
level: 3
name: DL-BASE-RiskSuffixes
type: DL
description: 敏感文件后缀
expr: (\\|\/).*(.rar|.zip|.tar|.tar.gz|.mdb|.dtd|.chm)$
mode: match(urlDecode(header_uri))
- id: 306004
level: 1
name: DL-BASE-RiskFile
type: DL
description: 可能存在风险的文件
expr: .*(web.xml|www.rar|wwwroot.rar|log4net.xml|server.xml|applicationContext.xml|jdbc.properties|server.properties)$
mode: match(urlDecode(header_uri))
status: 0
- category_id: c_16
category:
en: malicious scan
zh: 恶意扫描
description:
en: Detects whether a website has been scanned for malware.
zh: 检测网站是否被恶意扫描。
rules:
- id: 316001
level: 3
name: SS-Protocol-Scan
type: SS
description: 使用不常见协议对网站发起探测
expr: (TRACE|PUT|DELETE|OPTIONS).*
mode: match(header_method)
- id: 316002
level: 3
name: SS-Masscan
type: SS
description: 使用Masscan进行扫描
expr: ([^\x0A\x0D]*masscan)
mode: match(header_User-Agent)
- id: 316003
level: 3
name: SS-OpenVAS
type: SS
description: 使用OpenVAS进行扫描
expr: '[^\x0A\x0D]*OpenVAS'
mode: match(header_User-Agent)
- id: 316004
level: 4
name: SS-Webfuck
type: SS
description: 使用Webfuck进行扫描
expr: '[^\x0A\x0D]*WebFuck|[^\x0A\x0D]*T0PHackTeam'
mode: match(header_User-Agent)
- id: 316005
level: 3
name: SS-Nikto
type: SS
description: 使用Nikto进行扫描
expr: .{0,50}Nikto
mode: match(header_User-Agent)
- id: 316006
level: 2
name: SS-Sqlmap
type: SS
description: 使用sqlmap进行注入
expr: (sqlmap\/[0-9]{1}.*-dev-)
mode: match(header_User-Agent)
status: 0
- category_id: c_15
category:
en: XXE attack detection
zh: XXE 攻击检测
description:
en: Due to the XML processor there is an external entity reference in the XML file. An attacker could use an external entity to steal internal and shared files using URI file handlers, listen on internal scan ports, execute remote code, and perform denial-of-service attacks.
zh: 由于 XML 处理器在XML 文件中存在外部实体引用。攻击者可利用外部实体窃取使用 URI 文件处理器的内部文件和共享文件、监听内部扫描端口、执行远程代码和实施拒绝服务攻击。
rules:
- id: 315001
level: 2
name: GR-BASE-XMLInjection
type: GR
description: 一般xml注入
expr: (<!entity.*(system|internal) \"(file|php://|phar|ftp|http).*\">)
mode: match(urlDecode(body_buf))
status: 0
- category_id: c_19
category:
en: SSTI template injection detection
zh: SSTI 模板注入检测
description:
en: Inject malicious code into the template engine, causing the server to perform unexpected operations or leak sensitive information.
zh: 注入恶意代码到模板引擎中,导致服务器执行非预期操作或泄露敏感信息。
rules:
- id: 319003
level: 3
name: Other_SSTI
type: Other
description: SSTI模板注入漏洞
expr: ({\w{1,}(\*|\+|\-|\/)\w{1,}})
mode: match(urlDecode(header_uri|body_buf))
status: 0
- category_id: c_18
category:
en: Nday attack detection
zh: Nday 攻击检测
description:
en: Detect possible Nday attacks and prevent attacks and intrusions on the system by exploiting undisclosed vulnerabilities.
zh: 检测可能的 Nday 攻击,防止利用尚未公开的漏洞对系统进行攻击和入侵。
rules:
- id: 318001
level: 1
name: FAPPV-JAVA-Log4j2
type: FAPPV
description: 针对CVE-2021-44228的探测
expr: (\${jndi:(ldap|rmi):.*})
mode: match(urlDecode(header_uri|body_buf))
- id: 318002
level: 3
name: FAPPV-Grafana-Plugin
type: FAPPV
description: 针对CVE-2021-43798 Grafana插件任意文件读取漏洞
expr: (/public/plugins/.*/(../){1,})
mode: match(urlDecode(header_uri))
- id: 318003
level: 2
name: FAPPV-RCE-Apache-httpd
type: FAPPV
description: 针对CVE-2021-41773 apache httpd server任意文件读取漏洞
expr: ((.%2e/){1,4}(%2e%2e/){0,4})
mode: match(urlDecode(header_uri))
- id: 318004
level: 3
name: FAPPV-BT-pma
type: FAPPV
description: 宝塔phpmyadmin未授权访问漏洞
expr: (:888/pma$)
mode: match(urlDecode(header_path))
- id: 318005
level: 1
name: FAPPV-ThinkPHP5-1
type: FAPPV
description: thinkphp5.0远程命令执行漏洞
expr: ((s=index\/\\think\\app\/invokefunction).*(system|call_user_func_array|passthru|exec|shell_exec))
mode: match(urlDecode(header_uri))
- id: 318006
level: 1
name: FAPPV-ThinkPHP5-2
type: FAPPV
description: thinkphp5.1远程命令执行漏洞
expr: ((index\/\\think\\).*(request|template|view|Container).*(system|call_user_func_array|passthru|exec|shell_exec))
mode: match(urlDecode(header_uri))
- id: 318007
level: 2
name: FAPPV-Wordpress-1
type: FAPPV
description: wordpress xmlrpc远程代码执行漏洞
expr: (<methodName>(system|pingback|wp).*<\/methodName>)
mode: match(urlDecode(substr(body_buf,0,1024)))
- id: 318008
level: 1
name: FAPPV_Conflunce-1
type: FAPPV
description: 针对CVE-2022-26134 conflunce远程代码执行漏洞
expr: \$\{.*\(.*com.opensymphony.webwork.ServletActionContext.*getmethod\("
mode: match(urlDecode(header_uri|body_buf))
status: 0
- category_id: c_20
category:
en: Other attack detection
zh: 其它攻击检测
description:
en: Attacks caused by the security of the web server itself and other software configuration security or vulnerabilities.
zh: 由于Web服务器本身安全和其他软件配置安全或漏洞引起的攻击。
rules:
- id: 319001
level: 1
name: Other_JAVA-Spring-core
type: Other
description: spring core spring bean rce漏洞
expr: (class\.\w+|Class\.\w+|\w+\.class\.\w+|\w+\.Class\.\w+)
mode: match(urlDecode(header_uri|body_buf))
- id: 319002
level: 2
name: Other_JAVA-Spring-BASE-1
type: Other
description: 针对CVE-2022-22965 spring远程命令执行漏洞
expr: suffix=.jsp\S{1,100}(directory=webapps/ROOT)
mode: match(urlDecode(header_uri|body_buf))
- id: 319004
level: 3
name: Other_JAVA-SpringCloud
type: Other_JAVA
description: CVE-2022-22963 SpringCloud Function远程命令执行漏洞
expr: (spring.cloud.function.routing-expression:.*T\()
mode: match(urlDecode(substr(body_buf,0,1024)))
status: 0
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
CREATE TABLE waf_services ( CREATE TABLE waf_services (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
gateway_name VARCHAR(255) NOT NULL, gateway_name VARCHAR(255) NOT NULL,
port INTEGER NOT NULL,
namespace VARCHAR(255) NOT NULL, namespace VARCHAR(255) NOT NULL,
region_code VARCHAR(50) NOT NULL, region_code VARCHAR(50) NOT NULL,
host TEXT NOT NULL, -- Stored as comma-separated string
mode VARCHAR(50) NOT NULL, mode VARCHAR(50) NOT NULL,
rule_num INTEGER DEFAULT 0, rule_num INTEGER DEFAULT 0,
attack_num INTEGER DEFAULT 0, attack_num INTEGER DEFAULT 0,
rule_category_status JSONB NOT NULL rule_category_status JSON,
status INTEGER NOT NULL,
port INTEGER NOT NULL
); );
-- Create waf_rules table -- Create waf_rules table
...@@ -33,7 +33,7 @@ CREATE TABLE waf_rule_categories ( ...@@ -33,7 +33,7 @@ CREATE TABLE waf_rule_categories (
description_en TEXT, description_en TEXT,
description_zh TEXT, description_zh TEXT,
status INTEGER NOT NULL, status INTEGER NOT NULL,
rules JSONB NOT NULL rules JSON NOT NULL
); );
-- Add indexes for better query performance -- Add indexes for better query performance
......
module gitlab.com/tensorsecurity-rd/waf-console module gitlab.com/tensorsecurity-rd/waf-console
go 1.22.1 go 1.20
require ( require (
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
gitlab.com/security-rd/go-pkg v0.2.5
gorm.io/driver/mysql v1.5.0 gorm.io/driver/mysql v1.5.0
gorm.io/gorm v1.25.12 gorm.io/gorm v1.25.12
k8s.io/apimachinery v0.27.2 k8s.io/apimachinery v0.27.2
...@@ -42,7 +41,7 @@ require ( ...@@ -42,7 +41,7 @@ require (
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.27.2 // indirect k8s.io/api v0.27.2 // indirect
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect
k8s.io/klog/v2 v2.90.1 // indirect k8s.io/klog/v2 v2.90.1 // indirect
...@@ -53,10 +52,7 @@ require ( ...@@ -53,10 +52,7 @@ require (
sigs.k8s.io/yaml v1.3.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect
) )
require ( require github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/inconshreveable/mousetrap v1.1.0 // indirect
)
require ( require (
github.com/bytedance/sonic v1.12.1 // indirect github.com/bytedance/sonic v1.12.1 // indirect
...@@ -89,5 +85,3 @@ require ( ...@@ -89,5 +85,3 @@ require (
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect google.golang.org/protobuf v1.34.2 // indirect
) )
replace gitlab.com/security-rd/go-pkg => scm.tensorsecurity.cn/tensorsecurity-rd/go-pkg v0.2.101
...@@ -58,7 +58,6 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh ...@@ -58,7 +58,6 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
...@@ -69,7 +68,6 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 ...@@ -69,7 +68,6 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
...@@ -106,13 +104,10 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ ...@@ -106,13 +104,10 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
...@@ -135,7 +130,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN ...@@ -135,7 +130,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
...@@ -169,10 +163,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m ...@@ -169,10 +163,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c h1:Hww8mOyEKTeON4bZn7FrlLismspbPc1teNRUVH7wLQ8= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c h1:Hww8mOyEKTeON4bZn7FrlLismspbPc1teNRUVH7wLQ8=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
...@@ -181,7 +173,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb ...@@ -181,7 +173,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
...@@ -253,7 +244,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ ...@@ -253,7 +244,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
...@@ -362,8 +352,6 @@ k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3 ...@@ -362,8 +352,6 @@ k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3
k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU= k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
scm.tensorsecurity.cn/tensorsecurity-rd/go-pkg v0.2.101 h1:fmZdjUOeCwXnGRsq4cmaIbJCT+FIfjZkUJR6My2sJ3A=
scm.tensorsecurity.cn/tensorsecurity-rd/go-pkg v0.2.101/go.mod h1:7iA3d/FiV1buGqWtcrcSH1/wlT7DNQpMmxzBtq3/zbY=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
......
...@@ -2,12 +2,12 @@ package controller ...@@ -2,12 +2,12 @@ package controller
import ( import (
"context" "context"
"strconv"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gitlab.com/tensorsecurity-rd/waf-console/internal/service" "gitlab.com/tensorsecurity-rd/waf-console/internal/service"
"gitlab.com/tensorsecurity-rd/waf-console/internal/utils" "gitlab.com/tensorsecurity-rd/waf-console/internal/utils"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/generated/clientset/versioned"
"gorm.io/gorm" "gorm.io/gorm"
) )
...@@ -15,9 +15,9 @@ type WafController struct { ...@@ -15,9 +15,9 @@ type WafController struct {
service service.Service service service.Service
} }
func NewWafController(client *versioned.Clientset, db *gorm.DB) *WafController { func NewWafController(clusterClientManager *utils.ClusterClientManager, db *gorm.DB) *WafController {
return &WafController{ return &WafController{
service: service.NewWafService(client, db), service: service.NewWafService(clusterClientManager, db),
} }
} }
...@@ -26,7 +26,9 @@ func (c *WafController) Waf(ctx *gin.Context) { ...@@ -26,7 +26,9 @@ func (c *WafController) Waf(ctx *gin.Context) {
defer cancel() defer cancel()
gatewayName := ctx.Param("gateway_name") gatewayName := ctx.Param("gateway_name")
waf, err := c.service.GetWaf(ctx1, gatewayName) regionCode := ctx.Param("region_code")
namespace := ctx.Param("namespace")
waf, err := c.service.GetWaf(ctx1, regionCode, namespace, gatewayName)
if err != nil { if err != nil {
// logging.Get().Err(err).Msgf("get waf") // logging.Get().Err(err).Msgf("get waf")
utils.AssembleResponse(ctx, nil, err) utils.AssembleResponse(ctx, nil, err)
...@@ -89,6 +91,24 @@ func (c *WafController) UpdateMode(ctx *gin.Context) { ...@@ -89,6 +91,24 @@ func (c *WafController) UpdateMode(ctx *gin.Context) {
utils.AssembleResponse(ctx, nil, nil) utils.AssembleResponse(ctx, nil, nil)
} }
func (c *WafController) UpdateRule(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var req service.RuleRequest
if err := ctx.BindJSON(&req); err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
err := c.service.UpdateRule(ctx1, &req)
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, nil, nil)
}
func (c *WafController) SaveRuleCategoryToDB(ctx *gin.Context) { func (c *WafController) SaveRuleCategoryToDB(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
...@@ -100,3 +120,87 @@ func (c *WafController) SaveRuleCategoryToDB(ctx *gin.Context) { ...@@ -100,3 +120,87 @@ func (c *WafController) SaveRuleCategoryToDB(ctx *gin.Context) {
} }
utils.AssembleResponse(ctx, nil, nil) utils.AssembleResponse(ctx, nil, nil)
} }
func (c *WafController) EnableListenerWaf(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var req service.EnableListenerWafReq
if err := ctx.BindJSON(&req); err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
err := c.service.EnableListenerWaf(ctx1, &req)
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, nil, nil)
}
func (c *WafController) EnableGatewayWaf(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var req service.EnableGatewayWafReq
if err := ctx.BindJSON(&req); err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
err := c.service.EnableGatewayWaf(ctx1, &req)
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, nil, nil)
}
func (c *WafController) DeleteListenerWaf(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
regionCode := ctx.Param("region_code")
namespace := ctx.Param("namespace")
gatewayName := ctx.Param("gateway_name")
port, err := strconv.Atoi(ctx.Param("port"))
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
err = c.service.DeleteListenerWaf(ctx1, &service.DeleteListenerReq{
GatewateInfo: service.GatewateInfo{
RegionCode: regionCode,
Namespace: namespace,
GatewayName: gatewayName,
},
Port: port,
})
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, nil, nil)
}
func (c *WafController) DeleteGatewayWaf(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
regionCode := ctx.Param("region_code")
namespace := ctx.Param("namespace")
gatewayName := ctx.Param("gateway_name")
err := c.service.DeleteGatewayWaf(ctx1, &service.GatewateInfo{
RegionCode: regionCode,
Namespace: namespace,
GatewayName: gatewayName,
})
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, nil, nil)
}
...@@ -18,8 +18,16 @@ func (h *HostList) Scan(src interface{}) error { ...@@ -18,8 +18,16 @@ func (h *HostList) Scan(src interface{}) error {
} }
type RuleCategoryStatus struct { type RuleCategoryStatus struct {
CategoryID string `json:"category_id"` CategoryID []string `json:"category_id"`
Status int `json:"status"` Status int `json:"status"`
}
func (r *RuleCategoryStatus) Scan(src interface{}) error {
return json.Unmarshal(src.([]byte), r)
}
func (r RuleCategoryStatus) Value() (driver.Value, error) {
return json.Marshal(r)
} }
type RuleCategoryStatusList []RuleCategoryStatus type RuleCategoryStatusList []RuleCategoryStatus
...@@ -32,17 +40,22 @@ func (r *RuleCategoryStatusList) Scan(src interface{}) error { ...@@ -32,17 +40,22 @@ func (r *RuleCategoryStatusList) Scan(src interface{}) error {
return json.Unmarshal(src.([]byte), r) return json.Unmarshal(src.([]byte), r)
} }
const (
WafStatusEnable = 0
WafStatusDisable = 1
WafStatusUnknown = 2
)
type WafService struct { type WafService struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement"` ID uint `gorm:"column:id;primaryKey;autoIncrement"`
GatewayName string `gorm:"column:gateway_name"` GatewayName string `gorm:"column:gateway_name"`
Port int `gorm:"column:port"` Namespace string `gorm:"column:namespace"`
Namespace string `gorm:"column:namespace"` RegionCode string `gorm:"column:region_code"`
RegionCode string `gorm:"column:region_code"` Mode string `gorm:"column:mode"`
Host HostList `gorm:"column:host"` RuleNum int `gorm:"column:rule_num"`
Mode string `gorm:"column:mode"` AttackNum int `gorm:"column:attack_num"`
RuleNum int `gorm:"column:rule_num"` RuleCategoryStatus *RuleCategoryStatus `gorm:"column:rule_category_status;type:json"`
AttackNum int `gorm:"column:attack_num"` Host HostList `gorm:"column:host"`
RuleCategoryStatus RuleCategoryStatusList `gorm:"column:rule_category_status;type:json"`
} }
func (WafService) TableName() string { func (WafService) TableName() string {
...@@ -101,3 +114,16 @@ func (r *WafRuleCategory) Scan(src interface{}) error { ...@@ -101,3 +114,16 @@ func (r *WafRuleCategory) Scan(src interface{}) error {
func (r WafRuleCategory) Value() (driver.Value, error) { func (r WafRuleCategory) Value() (driver.Value, error) {
return json.Marshal(r) return json.Marshal(r)
} }
type GatewayListener struct {
ID int `gorm:"column:id;primaryKey;autoIncrement"`
GatewayName string `gorm:"column:gateway_name"`
Namespace string `gorm:"column:namespace"`
RegionCode string `gorm:"column:region_code"`
Port int `gorm:"column:port"`
Enable bool `gorm:"column:enable"`
}
func (GatewayListener) TableName() string {
return "gateway_listeners"
}
package service
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
"github.com/hashicorp/golang-lru/v2/expirable"
"gitlab.com/security-rd/go-pkg/logging"
"gitlab.com/tensorsecurity-rd/waf-console/internal/model"
)
var fakeData = `
{
"data": {
"87.236.176.199": {
"samples": [],
"tags_classes": [],
"judgments": [
"Scanner",
"Zombie",
"Dynamic IP",
"Spam"
],
"intelligences": {
"threatbook_lab": [
{
"source": "ThreatBook Labs",
"confidence": 75,
"expired": false,
"intel_tags": [],
"find_time": "2023-02-27 12:52:17",
"intel_types": [
"Spam"
],
"update_time": "2024-08-18 17:04:49"
},
{
"source": "ThreatBook Labs",
"confidence": 80,
"expired": false,
"intel_tags": [],
"find_time": "2023-02-27 12:14:00",
"intel_types": [
"Dynamic IP"
],
"update_time": "2023-02-27 12:14:00"
},
{
"source": "ThreatBook Labs",
"confidence": 75,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-19 03:38:38",
"intel_types": [
"Scanner"
],
"update_time": "2024-08-22 10:40:46"
},
{
"source": "ThreatBook Labs",
"confidence": 85,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-17 09:00:13",
"intel_types": [
"Spam"
],
"update_time": "2024-08-15 09:00:12"
},
{
"source": "ThreatBook Labs",
"confidence": 75,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-16 11:16:41",
"intel_types": [
"Zombie"
],
"update_time": "2023-07-05 12:34:57"
},
{
"source": "ThreatBook Labs",
"confidence": 75,
"expired": true,
"intel_tags": [],
"find_time": "2023-05-10 19:58:16",
"intel_types": [
"Scanner"
],
"update_time": "2023-06-21 03:23:22"
},
{
"source": "ThreatBook Labs",
"confidence": 85,
"expired": true,
"intel_tags": [],
"find_time": "2023-02-27 12:23:46",
"intel_types": [
"Spam",
"Zombie"
],
"update_time": "2024-07-20 18:35:32"
},
{
"source": "ThreatBook Labs",
"confidence": 75,
"expired": true,
"intel_tags": [],
"find_time": "2022-10-15 12:42:35",
"intel_types": [
"Scanner"
],
"update_time": "2022-10-22 09:11:17"
}
],
"x_reward": [],
"open_source": [
{
"source": "Open Source ",
"confidence": 50,
"expired": false,
"intel_tags": [],
"find_time": "2024-06-05 15:47:36",
"intel_types": [
"Malware"
],
"update_time": "2024-06-06 09:23:14"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2024-03-05 06:00:51",
"intel_types": [
"Suspicious"
],
"update_time": "2024-08-14 04:17:28"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2023-12-03 09:31:12",
"intel_types": [
"Suspicious"
],
"update_time": "2024-08-23 02:52:17"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2023-12-02 11:11:32",
"intel_types": [
"Suspicious"
],
"update_time": "2024-08-22 03:06:20"
},
{
"source": "Open Source ",
"confidence": 70,
"expired": false,
"intel_tags": [],
"find_time": "2023-11-29 09:39:12",
"intel_types": [
"Scanner"
],
"update_time": "2024-07-01 06:24:26"
},
{
"source": "cinsscore.com",
"confidence": 50,
"expired": false,
"intel_tags": [],
"find_time": "2023-11-11 02:40:16",
"intel_types": [
"Suspicious"
],
"update_time": "2024-08-10 01:30:20"
},
{
"source": "binarydefense.com",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2023-03-17 01:45:16",
"intel_types": [
"Malware"
],
"update_time": "2024-08-22 01:17:11"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2023-01-08 19:58:32",
"intel_types": [
"Suspicious"
],
"update_time": "2024-06-11 10:43:24"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-30 02:55:49",
"intel_types": [
"Suspicious"
],
"update_time": "2024-05-18 03:38:29"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-30 00:20:35",
"intel_types": [
"Suspicious"
],
"update_time": "2024-08-05 04:13:24"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-30 00:04:41",
"intel_types": [
"Suspicious"
],
"update_time": "2022-10-05 00:24:23"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-23 18:04:19",
"intel_types": [
"Suspicious"
],
"update_time": "2024-08-06 06:07:27"
},
{
"source": "Open Source ",
"confidence": 65,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-23 18:00:31",
"intel_types": [
"Suspicious"
],
"update_time": "2024-08-06 06:08:33"
},
{
"source": "blocklist.de",
"confidence": 55,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-22 15:57:53",
"intel_types": [
"Scanner"
],
"update_time": "2024-08-06 03:25:56"
},
{
"source": "Open Source ",
"confidence": 55,
"expired": false,
"intel_tags": [],
"find_time": "2022-09-16 14:51:57",
"intel_types": [
"Malware"
],
"update_time": "2024-08-23 15:00:39"
},
{
"source": "Open Source ",
"confidence": 50,
"expired": true,
"intel_tags": [],
"find_time": "2024-01-20 01:33:37",
"intel_types": [
"Scanner"
],
"update_time": "2024-08-22 01:18:11"
}
]
},
"scene": "",
"basic": {
"carrier": "Constantine Cybersecurity Ltd.",
"location": {
"country": "United Kingdom",
"province": "England",
"city": "Leeds",
"lng": "-1.549557",
"lat": "53.800302",
"country_code": "GB"
}
},
"asn": {
"rank": 4,
"info": "ITECOM-ASN, NL",
"number": 29529
},
"ports": [
{
"port": 80,
"module": "http",
"product": "",
"version": "",
"detail": ""
},
{
"port": 443,
"module": "https",
"product": "",
"version": "",
"detail": ""
}
],
"cas": [
{
"protocol": "https",
"port": 443,
"digital_certificate": {
"subject": "CloudFlare Origin Certificate",
"issuer": "",
"fingerprint": "857b7363019f1bf550375d56fa1f483ffb72bdef",
"purpose": "SSL client|SSL server|Netscape SSL server|Any Purpose|Any Purpose CA|OCSP helper",
"verify": "SHA256withECDSA",
"status": "0",
"revoked": false,
"begin": "2021-07-19 18:53:00",
"end": "2036-07-15 18:53:00",
"status_desc": "Valid",
"serial_number": "738a81454f135c291ee8b3264243964d29dba125",
"revoked_time": ""
}
}
],
"update_time": "2024-08-22 10:40:46",
"rdns_list": [
{
"rdns": "keen.monitoring.internet-measurement.com",
"get_time": "2023-12-12 00:00:00"
}
],
"sum_cur_domains": "3"
}
},
"response_code": 0,
"verbose_msg": "OK"
}`
const ipReputation = "https://api.threatbook.cn/v3/scene/ip_reputation"
const ipQuery = "https://api.threatbook.cn/v3/ip/query"
type ipService struct {
URL string
ApiKey string
ipQueryUrl string
ipReputationUrl string
// ipInfoMap map[string]IpInfo
useCachedIPInfo bool
ipInfoCache *expirable.LRU[string, IpInfo]
}
// func NewIpService(url, apiKey string, useCachedIPInfo bool) Service {
// return &ipService{
// URL: url,
// ApiKey: apiKey,
// ipQueryUrl: fmt.Sprintf("%s?apikey=%s&resource=", ipQuery, apiKey),
// ipReputationUrl: fmt.Sprintf("%s?apikey=%s&resource=", ipReputation, apiKey),
// // ipInfoMap: make(map[string]IpInfo),
// ipInfoCache: expirable.NewLRU[string, IpInfo](2048, nil, time.Minute*30),
// useCachedIPInfo: useCachedIPInfo,
// }
// }
func toModel(info *IpInfo) *model.IPInfo {
if info == nil {
return nil
}
sumCurDomains, err := strconv.Atoi(info.SumCurDomains)
if err != nil {
logging.Get().Err(err).Msgf("parse SumCurDomains: %s", info.SumCurDomains)
}
lon, err := strconv.ParseFloat(info.Basic.Location.Longitude, 32)
if err != nil {
logging.Get().Err(err).Msgf("parse Longitude: %s", info.Basic.Location.Longitude)
}
lat, err := strconv.ParseFloat(info.Basic.Location.Latitude, 32)
if err != nil {
logging.Get().Err(err).Msgf("parse Longitude: %s", info.Basic.Location.Latitude)
}
ipInfo := &model.IPInfo{
Carrier: info.Basic.Carrier,
Location: model.Location{
Country: info.Basic.Location.Country,
CountryCode: info.Basic.Location.CountryCode,
Province: info.Basic.Location.Province,
City: info.Basic.Location.City,
Longitude: lon,
Latitude: lat,
},
OSSIntelligences: []model.Intelligence{},
OnlineIntelligences: []model.Intelligence{},
Ports: []model.Port{},
Samples: []model.Sample{},
Cas: []model.CAS{},
Rdnses: []model.RDNS{},
Scene: info.Scene,
SumCurDomains: sumCurDomains,
TagsClasses: []model.TagsClass{},
Asn: model.ASN{
Number: info.ASN.Number,
Info: info.ASN.Info,
RiskRank: info.ASN.Rank,
},
Judgments: []string{},
}
if len(info.Judgments) > 0 {
ipInfo.Judgments = append(ipInfo.Judgments, info.Judgments...)
}
for _, intell := range info.Intelligences.OpenSource {
findTime, err := time.Parse("2006-01-02 15:04:05", intell.FindTime)
if err != nil {
logging.Get().Err(err).Msgf("FindTime :%s", intell.FindTime)
}
updateTime, err := time.Parse("2006-01-02 15:04:05", intell.UpdateTime)
if err != nil {
logging.Get().Err(err).Msgf("UpdateTime :%s", intell.UpdateTime)
}
intelTags := []model.TagsClass{}
for _, tag := range intell.IntelTags {
intelTags = append(intelTags, model.TagsClass{
TagsType: tag.TagsType,
Tags: strings.Join(tag.Tags, ","),
})
}
ipInfo.OSSIntelligences = append(ipInfo.OSSIntelligences, model.Intelligence{
Source: intell.Source,
FindTime: findTime.UnixMilli(),
UpdateTime: updateTime.UnixMilli(),
Confidence: intell.Confidence,
Expired: intell.Expired,
IntelTypes: intell.IntelTypes,
IntelTags: intelTags,
})
}
for _, intell := range info.Intelligences.ThreatbookLab {
findTime, err := time.Parse("2006-01-02 15:04:05", intell.FindTime)
if err != nil {
logging.Get().Err(err).Msgf("FindTime :%s", intell.FindTime)
}
updateTime, err := time.Parse("2006-01-02 15:04:05", intell.UpdateTime)
if err != nil {
logging.Get().Err(err).Msgf("UpdateTime :%s", intell.UpdateTime)
}
intelTags := []model.TagsClass{}
for _, tag := range intell.IntelTags {
intelTags = append(intelTags, model.TagsClass{
TagsType: tag.TagsType,
Tags: strings.Join(tag.Tags, ","),
})
}
ipInfo.OnlineIntelligences = append(ipInfo.OnlineIntelligences, model.Intelligence{
Source: intell.Source,
FindTime: findTime.UnixMilli(),
UpdateTime: updateTime.UnixMilli(),
Confidence: intell.Confidence,
Expired: intell.Expired,
IntelTypes: intell.IntelTypes,
IntelTags: intelTags,
})
}
for _, port := range info.Ports {
ipInfo.Ports = append(ipInfo.Ports, model.Port{
Port: int16(port.Port),
Module: port.Module,
Product: port.Product,
Version: port.Version,
Detail: port.Detail,
})
}
for _, sample := range info.Samples {
scanTime, err := time.Parse("2006-01-02 15:04:05", sample.ScanTime)
if err != nil {
logging.Get().Err(err).Msgf("scanTime :%s", sample.ScanTime)
}
ipInfo.Samples = append(ipInfo.Samples, model.Sample{
Hash: sample.Hash,
ScanTime: scanTime.UnixMilli(),
Ratio: sample.Ratio,
MalwareType: sample.MalwareType,
MalwareFamily: sample.MalwareFamily,
})
}
for _, cas := range info.CAS {
ipInfo.Cas = append(ipInfo.Cas, model.CAS{
Protocol: cas.Protocol,
Port: cas.Port,
Period: cas.Period,
DigitalCertificate: model.Certificate{
Subject: cas.DigitalCertificate.Subject,
Issuer: cas.DigitalCertificate.Issuer,
Fingerprint: cas.DigitalCertificate.Fingerprint,
Purpose: cas.DigitalCertificate.Purpose,
Verify: cas.DigitalCertificate.Verify,
Status: cas.DigitalCertificate.Status,
Revoked: cas.DigitalCertificate.Revoked,
Begin: cas.DigitalCertificate.Begin,
End: cas.DigitalCertificate.End,
StatusDesc: cas.DigitalCertificate.StatusDesc,
SerialNumber: cas.DigitalCertificate.SerialNumber,
RevokedTime: cas.DigitalCertificate.RevokedTime,
},
})
}
for _, dns := range info.RDNSList {
ipInfo.Rdnses = append(ipInfo.Rdnses, model.RDNS{
RDNS: dns.RDNS,
GetTime: dns.GetTime,
})
}
for _, tagclass := range info.TagsClasses {
ipInfo.TagsClasses = append(ipInfo.TagsClasses, model.TagsClass{
TagsType: tagclass.TagsType,
Tags: strings.Join(tagclass.Tags, ","),
})
}
return ipInfo
}
func (s *ipService) QueryIP(ip string) (*model.IPInfo, error) {
ipInfo := IpInfo{}
// ipI, ok := s.ipInfoMap[ip]
ipI, ok := s.ipInfoCache.Get(ip)
if ok && s.useCachedIPInfo {
logging.Get().Info().Msg("hit ipinfo cache")
ipInfo = ipI
ipQueryInfo := toModel(&ipInfo)
// isMalicious, _ := s.isMalicious(ip)
// ipQueryInfo.IsMalicious = isMalicious
return ipQueryInfo, nil
} else {
resp, err := http.DefaultClient.Get(s.ipQueryUrl + ip)
if err != nil {
return nil, err
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
logging.Get().Info().Msg(string(data))
var respData RespData
err = json.Unmarshal([]byte(data), &respData)
if err != nil {
return nil, err
}
if respData.ResponseCode != 0 {
return nil, fmt.Errorf("error occurs: %s", respData.VerboseMsg)
}
if info, ok := respData.Data[ip]; ok {
d, err := info.MarshalJSON()
if err != nil {
return nil, err
}
err = json.Unmarshal(d, &ipInfo)
if err != nil {
return nil, err
}
if s.useCachedIPInfo {
// s.ipInfoMap[ip] = ipInfo
s.ipInfoCache.Add(ip, ipInfo)
}
ipQueryInfo := toModel(&ipInfo)
isMalicious, _ := s.isMalicious(ip)
ipQueryInfo.IsMalicious = isMalicious
return ipQueryInfo, nil
}
}
return &model.IPInfo{}, nil
}
func (s *ipService) isMalicious(ip string) (bool, error) {
resp, err := http.DefaultClient.Get(s.ipReputationUrl + ip)
if err != nil {
return false, err
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return false, err
}
logging.Get().Info().Msg(string(data))
// fmt.Println(string(data))
var respData RespData
err = json.Unmarshal([]byte(data), &respData)
if err != nil {
return false, err
}
if reputation, ok := respData.Data[ip]; ok {
var rep Reputation
d, err := reputation.MarshalJSON()
if err != nil {
return false, err
}
err = json.Unmarshal(d, &rep)
if err != nil {
return false, err
}
return rep.IsMalicious, nil
}
return false, nil
}
package service
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"gitlab.com/tensorsecurity-rd/waf-console/internal/model"
)
var fakePrivateData = `{
"data": [
{
"ioc": "159.203.93.255",
"host": "10.65.135.204",
"intelligence": [
{
"judgments": [
"Exploit"
],
"severity": "low",
"ban": {
"banned": 1,
"reason": "The IP address belongs to DigitalOcean, LLC, it is recommended to assess and handle it accordingly."
},
"basic": {
"carrier": "DigitalOcean, LLC",
"location": {
"country": "美国",
"country_code": "US",
"province": "新泽西州",
"city": "克利夫顿",
"lng": -74.16366,
"lat": 40.858402
}
},
"asn": {
"number": "14061",
"info": "DIGITALOCEAN-ASN - DigitalOcean, LLC, US"
},
"ioc_type": "ipv4",
"confidence_level": "low",
"is_malicious": true,
"source_name": "微步在线-IP信誉",
"update_time": 1719268503000
}
]
}
],
"response_code": 0,
"verbose_msg": "success"
}`
type ipServicePrivate struct {
URL string
ApiKey string
// ipQueryUrl string
ipReputationUrl string
// ipInfoMap map[string]IpInfo
// useCachedIPInfo bool
// ipInfoCache *expirable.LRU[string, IPInfoPrivate]
}
// func NewIpServicePrivate(url, apiKey string, useCachedIPInfo bool) Service {
// var ipReputationUrl string
// reputationUrl := os.Getenv("IP_REPUTATION_URL")
// logging.Get().Info().Msgf("reputationUrl: %s", reputationUrl)
// if reputationUrl != "" {
// ipReputationUrl = reputationUrl
// } else {
// ipReputationUrl = fmt.Sprintf("%s?apikey=%s&resource=", ipReputation, apiKey)
// }
// logging.Get().Info().Msgf("ipReputationUrl: %s", ipReputationUrl)
// return &ipServicePrivate{
// URL: url,
// ApiKey: apiKey,
// ipReputationUrl: ipReputationUrl,
// }
// }
func (s *ipServicePrivate) QueryIP(ip string) (*model.IPInfo, error) {
url := s.ipReputationUrl + ip
respData, err := http.DefaultClient.Get(url)
if err != nil {
return nil, err
}
defer respData.Body.Close()
body, err := io.ReadAll(respData.Body)
if err != nil {
return nil, fmt.Errorf("query ip info failed: %w", err)
}
var resp IPInfoPrivateResp
if err := json.Unmarshal(body, &resp); err != nil {
return nil, fmt.Errorf("unmarshal response failed: %w", err)
}
if len(resp.Data) == 0 || len(resp.Data[0].Intelligence) == 0 {
return nil, fmt.Errorf("no data found for ip %s", ip)
}
info := resp.Data[0].Intelligence[0]
tagsClasses := make([]model.TagsClass, 0, 5)
for k, v := range info.TagsClasses {
for _, tag := range v {
tagsClasses = append(tagsClasses, model.TagsClass{
TagsType: k,
Tags: tag,
})
}
}
return &model.IPInfo{
Carrier: info.Basic.Carrier,
Location: model.Location{
Country: info.Basic.Location.Country,
CountryCode: info.Basic.Location.CountryCode,
Province: info.Basic.Location.Province,
City: info.Basic.Location.City,
Longitude: info.Basic.Location.Longitude,
Latitude: info.Basic.Location.Latitude,
},
Asn: model.ASN{
Number: func() int { n, _ := strconv.Atoi(info.ASN.Number); return n }(),
Info: info.ASN.Info,
},
Scene: info.Scene,
IsMalicious: info.IsMalicious,
Judgments: info.Judgments,
TagsClasses: tagsClasses,
}, nil
}
package service
import (
"encoding/json"
"fmt"
"reflect"
"testing"
"gitlab.com/tensorsecurity-rd/waf-console/internal/model"
)
func TestIPService_QueryIP(t *testing.T) {
type fields struct {
URL string
ApiKey string
}
type args struct {
ip string
}
tests := []struct {
name string
fields fields
args args
want *model.IPInfo
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &ipService{
URL: tt.fields.URL,
ApiKey: tt.fields.ApiKey,
}
got, err := s.QueryIP(tt.args.ip)
if (err != nil) != tt.wantErr {
t.Errorf("IPService.QueryIP() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("IPService.QueryIP() = %v, want %v", got, tt.want)
}
})
}
}
func TestParseIPInfo(t *testing.T) {
t.Run("test 1", func(t *testing.T) {
var respData RespData
err := json.Unmarshal([]byte(fakeData), &respData)
if err != nil {
t.Errorf("Unmarshal err %v", err)
}
if info, ok := respData.Data["87.236.176.199"]; ok {
var ipInfo IpInfo
d, err := info.MarshalJSON()
if err != nil {
t.Error(err)
}
err = json.Unmarshal(d, &ipInfo)
if err != nil {
t.Error(err)
}
fmt.Println(ipInfo.Judgments)
}
fmt.Println("ddddd")
})
}
func TestParseIPInfoPrivate(t *testing.T) {
t.Run("test 1", func(t *testing.T) {
var respData IPInfoPrivateResp
err := json.Unmarshal([]byte(fakePrivateData), &respData)
if err != nil {
t.Errorf("Unmarshal err %v", err)
}
if len(respData.Data) > 0 {
for _, v := range respData.Data {
fmt.Println(v)
}
}
fmt.Println("ddddd")
})
}
...@@ -4,8 +4,13 @@ import "context" ...@@ -4,8 +4,13 @@ import "context"
type Service interface { type Service interface {
// QueryIP(ip string) (*model.IPInfo, error) // QueryIP(ip string) (*model.IPInfo, error)
GetWaf(ctx context.Context, gatewayName string) (*Waf, error) GetWaf(ctx context.Context, regionCode, namespace, gatewayName string) (*WafService, error)
CreateWaf(ctx context.Context, req *CreateWafReq) (*Waf, error) CreateWaf(ctx context.Context, req *CreateWafReq) (*WafService, error)
UpdateMode(ctx context.Context, req *UpdateModeReq) (*Waf, error) UpdateMode(ctx context.Context, req *UpdateModeReq) (*WafService, error)
UpdateRule(ctx context.Context, req *RuleRequest) error
SaveRuleCategoryToDB(ctx context.Context) error SaveRuleCategoryToDB(ctx context.Context) error
EnableListenerWaf(ctx context.Context, req *EnableListenerWafReq) error
EnableGatewayWaf(ctx context.Context, req *EnableGatewayWafReq) error
DeleteGatewayWaf(ctx context.Context, req *GatewateInfo) error
DeleteListenerWaf(ctx context.Context, req *DeleteListenerReq) error
} }
...@@ -163,31 +163,62 @@ type IPInfoPrivateResp struct { ...@@ -163,31 +163,62 @@ type IPInfoPrivateResp struct {
VerboseMsg string `json:"verbose_msg"` VerboseMsg string `json:"verbose_msg"`
} }
type Waf struct { type WafService struct {
GatewayName string `json:"gateway_name"` GatewayName string `json:"gateway_name"`
Mode string `json:"mode"` Mode string `json:"mode"`
RuleNum int `json:"rule_num"` RuleNum int `json:"rule_num"`
AttackNum int `json:"attack_num"` AttackNum int `json:"attack_num"`
} // WAF configuration details } // WAF configuration details
type GatewateInfo struct {
GatewayName string `json:"gateway_name"`
Namespace string `json:"namespace"`
RegionCode string `json:"region_code"`
ApiGatewayCrn string `json:"gateway_crn"`
Hosts []string `json:"hosts"`
}
type CreateWafReq struct { type CreateWafReq struct {
RegionCode string `json:"region_code"` GatewateInfo
Namespace string `json:"namespace"` Port uint32 `json:"port"`
GatewayName string `json:"gateway_name"` Host []string `json:"host"`
Port uint32 `json:"port"` }
Host []string `json:"host"`
type DeleteWafReq struct {
GatewateInfo
Ports []int `json:"ports"`
} }
type RuleRequest struct { type RuleRequest struct {
GatewateInfo
CategoryID []string `json:"category_id"` CategoryID []string `json:"category_id"`
Status int `json:"status"` Status int `json:"status"`
} }
type WafMode string
const (
WafModeProtect WafMode = "protect"
WafModeAlert WafMode = "alert"
WafModePassthrough WafMode = "passthrough"
)
type UpdateModeReq struct { type UpdateModeReq struct {
Mode string `json:"mode"` Mode WafMode `json:"mode"`
GatewayName string `json:"gateway_name"` GatewayName string `json:"gateway_name"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
RegionCode string `json:"region_code"` RegionCode string `json:"region_code"`
}
type EnableListenerWafReq struct {
GatewateInfo
Enable bool `json:"enable"`
Port int `json:"port"`
}
type EnableGatewayWafReq struct {
GatewateInfo
Enable bool `json:"enable"`
} }
type WafRule struct { type WafRule struct {
...@@ -217,3 +248,21 @@ type WafRuleCategory struct { ...@@ -217,3 +248,21 @@ type WafRuleCategory struct {
Description Description `json:"description"` Description Description `json:"description"`
Rules []WafRule `json:"rules"` Rules []WafRule `json:"rules"`
} }
type GatewayListener struct {
GatewayName string `json:"gateway_name"`
Namespace string `json:"namespace"`
RegionCode string `json:"region_code"`
Port int `json:"port"`
Enable bool `json:"enable"`
}
type CreateListenerReq struct {
GatewateInfo
Port int `json:"port"`
}
type DeleteListenerReq struct {
GatewateInfo
Port int `json:"port"`
}
package service package service
import ( import (
"bytes"
"context" "context"
"encoding/json"
"fmt" "fmt"
"net/http"
"os" "os"
"strconv"
"strings"
"gitlab.com/tensorsecurity-rd/waf-console/internal/model" "gitlab.com/tensorsecurity-rd/waf-console/internal/model"
"gitlab.com/tensorsecurity-rd/waf-console/internal/utils"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/apis/waf.security.io/v1alpha1" "gitlab.com/tensorsecurity-rd/waf-console/pkg/apis/waf.security.io/v1alpha1"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/generated/clientset/versioned"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"gorm.io/gorm" "gorm.io/gorm"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
type wafService struct { type wafService struct {
client *versioned.Clientset clusterClientManager *utils.ClusterClientManager
db *gorm.DB db *gorm.DB
} }
func NewWafService(client *versioned.Clientset, db *gorm.DB) Service { func NewWafService(clusterClientManager *utils.ClusterClientManager, db *gorm.DB) Service {
return &wafService{client: client, db: db} return &wafService{clusterClientManager: clusterClientManager, db: db}
} }
func (s *wafService) GetWaf(ctx context.Context, gatewayName string) (*Waf, error) { func (s *wafService) GetWaf(ctx context.Context, regionCode, namespace, gatewayName string) (*WafService, error) {
waf := &Waf{ wafService := &model.WafService{}
GatewayName: gatewayName, err := s.db.Model(&model.WafService{}).Where("gateway_name = ? AND region_code = ? AND namespace = ?", gatewayName, regionCode, namespace).First(wafService).Error
Mode: "block", if err != nil {
RuleNum: 100, if err == gorm.ErrRecordNotFound {
AttackNum: 100, // Create new WAF service record if not found
wafService = &model.WafService{
RegionCode: regionCode,
Namespace: namespace,
GatewayName: gatewayName,
Mode: string(WafModeAlert),
}
if err := s.db.Create(wafService).Error; err != nil {
return nil, fmt.Errorf("failed to create WAF service: %v", err)
}
} else {
return nil, fmt.Errorf("failed to query WAF service: %v", err)
}
} }
return waf, nil return &WafService{
GatewayName: wafService.GatewayName,
Mode: wafService.Mode,
RuleNum: wafService.RuleNum,
AttackNum: wafService.AttackNum,
}, nil
} }
func (s *wafService) CreateWaf(ctx context.Context, req *CreateWafReq) (*Waf, error) { func (s *wafService) CreateWaf(ctx context.Context, req *CreateWafReq) (*WafService, error) {
// Create the WAF service resource
name := fmt.Sprintf("%s-%d", req.GatewayName, req.Port)
service := &v1alpha1.Service{ service := &v1alpha1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: req.GatewayName, Name: name,
Namespace: req.Namespace, Namespace: req.Namespace,
Labels: map[string]string{
"apigateway_name": req.GatewayName,
},
}, },
Spec: v1alpha1.ServiceSpec{ Spec: v1alpha1.ServiceSpec{
HostNames: req.Host, HostNames: req.Host,
...@@ -47,17 +74,126 @@ func (s *wafService) CreateWaf(ctx context.Context, req *CreateWafReq) (*Waf, er ...@@ -47,17 +74,126 @@ func (s *wafService) CreateWaf(ctx context.Context, req *CreateWafReq) (*Waf, er
Name: req.GatewayName, Name: req.GatewayName,
Namespace: req.Namespace, Namespace: req.Namespace,
}, },
Uri: &v1alpha1.StringMatch{
Prefix: "/",
},
LogConfig: &v1alpha1.LogConfig{
Enable: 1,
Level: "info",
},
Mode: "block",
}, },
} }
_, err := s.client.WafV1alpha1().Services(req.Namespace).Create(context.Background(), service, metav1.CreateOptions{})
// Get enabled rule categories from DB
var ruleCategories []model.WafRuleCategory
if err := s.db.Model(&model.WafRuleCategory{}).Where("status = ?", 0).Find(&ruleCategories).Error; err != nil {
return nil, fmt.Errorf("failed to get rule categories: %v", err)
}
// Get existing WAF service config if any
wafService := &model.WafService{}
err := s.db.Model(&model.WafService{}).Where("gateway_name = ? AND namespace = ? AND region_code = ?", req.GatewayName, req.Namespace, req.RegionCode).First(wafService).Error
if err != nil { if err != nil {
return nil, err if err == gorm.ErrRecordNotFound {
// Create new WAF service record if not found
wafService = &model.WafService{
RegionCode: req.RegionCode,
Namespace: req.Namespace,
GatewayName: req.GatewayName,
Mode: string(WafModeAlert),
Host: model.HostList(req.Host),
}
if err := s.db.Create(wafService).Error; err != nil {
return nil, fmt.Errorf("failed to create WAF service: %v", err)
}
} else {
return nil, fmt.Errorf("failed to query WAF service: %v", err)
}
}
// Determine which rule categories to enable
var enabledCategories []model.WafRuleCategory
if wafService.RuleCategoryStatus != nil && len(wafService.RuleCategoryStatus.CategoryID) > 0 {
// Only include categories not already enabled
for _, category := range ruleCategories {
for _, id := range wafService.RuleCategoryStatus.CategoryID {
if id == category.CategoryID {
enabledCategories = append(enabledCategories, category)
continue
}
}
}
} else {
// Enable all categories if none specified
enabledCategories = ruleCategories
}
// Add rules from enabled categories
for _, category := range enabledCategories {
for _, rule := range category.Rules {
service.Spec.Rules = append(service.Spec.Rules, v1alpha1.Rule{
ID: rule.ID,
Level: rule.Level,
Name: rule.Name,
Type: rule.Type,
Description: rule.Description,
Expr: rule.Expr,
Mode: rule.Mode,
})
}
}
// Create the WAF service in Kubernetes
client := s.clusterClientManager.GetClient(req.RegionCode)
if client == nil {
return nil, fmt.Errorf("failed to get cluster client: %v", err)
}
if _, err := client.WafV1alpha1().Services(req.Namespace).Create(ctx, service, metav1.CreateOptions{}); err != nil {
return nil, fmt.Errorf("failed to create WAF service: %v", err)
} }
return nil, nil return nil, nil
} }
func (s *wafService) UpdateMode(ctx context.Context, req *UpdateModeReq) (*Waf, error) { func (s *wafService) DeleteListenerWaf(ctx context.Context, req *DeleteListenerReq) error {
client := s.clusterClientManager.GetClient(req.RegionCode)
if client == nil {
return fmt.Errorf("failed to get cluster client")
}
name := fmt.Sprintf("%s-%d", req.GatewayName, req.Port)
if err := client.WafV1alpha1().Services(req.Namespace).Delete(ctx, name, metav1.DeleteOptions{}); err != nil {
return fmt.Errorf("failed to delete WAF service: %v", err)
}
return nil
}
func (s *wafService) UpdateMode(ctx context.Context, req *UpdateModeReq) (*WafService, error) {
// Check if WAF service exists
wafService := &model.WafService{}
err := s.db.Model(&model.WafService{}).Where("gateway_name = ?", req.GatewayName).First(wafService).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
// Create new WAF service record if not found
wafService = &model.WafService{
RegionCode: req.RegionCode,
Namespace: req.Namespace,
GatewayName: req.GatewayName,
Mode: string(req.Mode),
}
if err := s.db.Create(wafService).Error; err != nil {
return nil, fmt.Errorf("failed to create WAF service: %v", err)
}
} else {
return nil, fmt.Errorf("failed to query WAF service: %v", err)
}
} else {
// Update mode if service exists
if err := s.db.Model(wafService).Update("mode", string(req.Mode)).Error; err != nil {
return nil, fmt.Errorf("failed to update WAF service mode: %v", err)
}
}
return nil, nil return nil, nil
} }
...@@ -131,3 +267,240 @@ func (s *wafService) SaveRuleCategoryToDB(ctx context.Context) error { ...@@ -131,3 +267,240 @@ func (s *wafService) SaveRuleCategoryToDB(ctx context.Context) error {
return nil return nil
} }
func (s *wafService) CreateListener(ctx context.Context, req *CreateListenerReq) (*GatewayListener, error) {
listener := &model.GatewayListener{}
err := s.db.Model(&model.GatewayListener{}).Where("gateway_name = ? AND namespace = ? AND region_code = ?", req.GatewayName, req.Namespace, req.RegionCode).First(listener).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
listener = &model.GatewayListener{
GatewayName: req.GatewayName,
Namespace: req.Namespace,
RegionCode: req.RegionCode,
Port: req.Port,
Enable: true,
}
err = s.db.Model(&model.GatewayListener{}).Create(listener).Error
if err != nil {
return nil, err
}
} else {
return nil, err
}
}
return &GatewayListener{
GatewayName: listener.GatewayName,
Namespace: listener.Namespace,
RegionCode: listener.RegionCode,
Port: listener.Port,
Enable: listener.Enable,
}, nil
}
func (s *wafService) DeleteListener(ctx context.Context, req *DeleteListenerReq) error {
listener := &model.GatewayListener{}
err := s.db.Model(&model.GatewayListener{}).Where("gateway_name = ? AND namespace = ? AND region_code = ?", req.GatewayName, req.Namespace, req.RegionCode).First(listener).Error
if err != nil {
return err
}
err = s.db.Model(&model.GatewayListener{}).Where("gateway_name = ? AND namespace = ? AND region_code = ?", req.GatewayName, req.Namespace, req.RegionCode).Delete(listener).Error
if err != nil {
return err
}
return nil
}
func (s *wafService) EnableListenerWaf(ctx context.Context, req *EnableListenerWafReq) error {
listener := &model.GatewayListener{}
err := s.db.Model(&model.GatewayListener{}).Where("gateway_name = ? AND namespace = ? AND region_code = ?", req.GatewayName, req.Namespace, req.RegionCode).First(listener).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
listener = &model.GatewayListener{
GatewayName: req.GatewayName,
Namespace: req.Namespace,
RegionCode: req.RegionCode,
Port: int(req.Port),
Enable: req.Enable,
}
err = s.db.Model(&model.GatewayListener{}).Create(listener).Error
if err != nil {
return err
}
} else {
return err
}
}
listener.Enable = req.Enable
err = s.db.Model(&model.GatewayListener{}).Where("gateway_name = ? AND namespace = ? AND region_code = ?", req.GatewayName, req.Namespace, req.RegionCode).Update("enable", req.Enable).Error
if err != nil {
return err
}
wafService := &model.WafService{}
err = s.db.Model(&model.WafService{}).Where("gateway_name = ? AND namespace = ? AND region_code = ?", req.GatewayName, req.Namespace, req.RegionCode).First(wafService).Error
if err != nil && err != gorm.ErrRecordNotFound {
return err
}
if listener.Enable {
s.CreateWaf(ctx, &CreateWafReq{
GatewateInfo: GatewateInfo{
GatewayName: req.GatewayName,
Namespace: req.Namespace,
RegionCode: req.RegionCode,
},
Port: uint32(req.Port),
Host: wafService.Host,
})
} else {
s.DeleteListenerWaf(ctx, &DeleteListenerReq{
GatewateInfo: GatewateInfo{
GatewayName: req.GatewayName,
Namespace: req.Namespace,
RegionCode: req.RegionCode,
},
Port: req.Port,
})
}
return nil
}
func (s *wafService) EnableGatewayWaf(ctx context.Context, req *EnableGatewayWafReq) error {
if req.Enable {
// Get listener list from API
body, err := json.Marshal(map[string]string{
"apigateway_crn": req.ApiGatewayCrn,
"region_code": req.RegionCode,
})
if err != nil {
return fmt.Errorf("failed to marshal request body: %v", err)
}
resp, err := http.Post("https://csm.console.test.tg.unicom.local/apigatewaymng/listener/lf-tst7/list_listeners", "application/json", bytes.NewBuffer(body))
if err != nil {
return fmt.Errorf("failed to get listener list: %v", err)
}
defer resp.Body.Close()
// Parse response
var listeners []struct {
ApigatewayCrn string `json:"apigateway_crn"`
Port uint32 `json:"port"`
Hosts []string `json:"hosts"`
}
if err := json.NewDecoder(resp.Body).Decode(&listeners); err != nil {
return fmt.Errorf("failed to parse listener list: %v", err)
}
// Create WAF for each listener
for _, listener := range listeners {
if _, err := s.CreateWaf(ctx, &CreateWafReq{
GatewateInfo: GatewateInfo{
GatewayName: req.GatewayName,
Namespace: req.Namespace,
RegionCode: req.RegionCode,
},
Port: uint32(listener.Port),
Host: listener.Hosts,
}); err != nil {
return fmt.Errorf("failed to create WAF for listener %d: %v", listener.Port, err)
}
}
} else {
s.DeleteGatewayWaf(ctx, &GatewateInfo{
GatewayName: req.GatewayName,
Namespace: req.Namespace,
RegionCode: req.RegionCode,
})
}
return nil
}
func (s *wafService) DeleteGatewayWaf(ctx context.Context, req *GatewateInfo) error {
client := s.clusterClientManager.GetClient(req.RegionCode)
if client == nil {
return fmt.Errorf("failed to get cluster client")
}
labelSelector := fmt.Sprintf("apigateway_name=%s", req.GatewayName)
if err := client.WafV1alpha1().Services(req.Namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: labelSelector}); err != nil {
return fmt.Errorf("failed to delete WAF service: %v", err)
}
return nil
}
func (s *wafService) UpdateRule(ctx context.Context, req *RuleRequest) error {
wafService := &model.WafService{}
err := s.db.Model(&model.WafService{}).Where("gateway_name = ?", req.GatewayName).First(wafService).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
// Create new WAF service record if not found
wafService = &model.WafService{
RegionCode: req.RegionCode,
Namespace: req.Namespace,
GatewayName: req.GatewayName,
Mode: string(WafModeAlert),
RuleCategoryStatus: &model.RuleCategoryStatus{
CategoryID: req.CategoryID,
Status: req.Status,
},
}
if err := s.db.Create(wafService).Error; err != nil {
return fmt.Errorf("failed to create WAF service: %v", err)
}
} else {
return fmt.Errorf("failed to query WAF service: %v", err)
}
} else {
// Update mode if service exists
if err := s.db.Model(wafService).Update("rule_category_status", model.RuleCategoryStatus{
CategoryID: req.CategoryID,
Status: req.Status,
}).Error; err != nil {
return fmt.Errorf("failed to update WAF service mode: %v", err)
}
}
return nil
}
func (s *wafService) ListListenerWafStatus(ctx context.Context, req *GatewateInfo) ([]*GatewayListener, error) {
client := s.clusterClientManager.GetClient(req.RegionCode)
if client == nil {
return nil, fmt.Errorf("failed to get cluster client")
}
listenerList, err := client.WafV1alpha1().Services(req.Namespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("apigateway_name=%s", req.GatewayName)})
if err != nil {
return nil, fmt.Errorf("failed to get listener list: %v", err)
}
listenerStatusList := []*GatewayListener{}
portList := []int{}
for _, listener := range listenerList.Items {
n := strings.LastIndex(listener.Name, "-")
if n == -1 {
return nil, fmt.Errorf("failed to get listener name: %v", listener.Name)
}
listenerPort := listener.Name[n+1:]
listenerPortInt, err := strconv.Atoi(listenerPort)
if err != nil {
return nil, fmt.Errorf("failed to get listener port: %v", err)
}
portList = append(portList, listenerPortInt)
}
for _, port := range portList {
listenerStatusList = append(listenerStatusList, &GatewayListener{
GatewayName: req.GatewayName,
Namespace: req.Namespace,
RegionCode: req.RegionCode,
Port: port,
Enable: true,
})
}
return listenerStatusList, nil
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment