Skip to content

Commit b73c707

Browse files
committed
fix: handle encoded POC set values
1 parent 75f4265 commit b73c707

5 files changed

Lines changed: 110 additions & 15 deletions

File tree

webscan/lib/eval_misc.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ func registerMiscDeclarations() []*exprpb.Decl {
2121
decls.NewOverload("tongda_date",
2222
[]*exprpb.Type{},
2323
decls.String)),
24+
decls.NewFunction("timestamp_second",
25+
decls.NewOverload("timestamp_second_zero",
26+
[]*exprpb.Type{},
27+
decls.Int)),
2428
}
2529
}
2630

@@ -47,5 +51,11 @@ func registerMiscImplementations() []*functions.Overload {
4751
return types.String(time.Now().Format("0601"))
4852
},
4953
},
54+
{
55+
Operator: "timestamp_second_zero",
56+
Function: func(value ...ref.Val) ref.Val {
57+
return types.Int(time.Now().Unix())
58+
},
59+
},
5060
}
5161
}

webscan/lib/eval_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"net/url"
1111
"strings"
1212
"testing"
13+
"time"
1314

1415
"github.com/google/cel-go/common/types"
1516
)
@@ -1393,3 +1394,19 @@ func TestMakeVarDecl(t *testing.T) {
13931394
})
13941395
}
13951396
}
1397+
1398+
func TestTimestampSecond(t *testing.T) {
1399+
before := time.Now().Unix()
1400+
result, err := Evaluate(GetBaseEnv(), "timestamp_second()", map[string]interface{}{})
1401+
if err != nil {
1402+
t.Fatal(err)
1403+
}
1404+
got, ok := result.Value().(int64)
1405+
if !ok {
1406+
t.Fatalf("timestamp_second() type = %T, want int64", result.Value())
1407+
}
1408+
after := time.Now().Unix()
1409+
if got < before || got > after {
1410+
t.Fatalf("timestamp_second() = %d, want [%d, %d]", got, before, after)
1411+
}
1412+
}

webscan/lib/poc_executor.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,10 @@ func cloneMap(tags map[string]string) map[string]string {
869869

870870
// evalset 执行CEL表达式并处理特殊类型结果
871871
func evalset(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (string, error) {
872+
if isPlainLiteral(expression, variableMap) {
873+
variableMap[k] = expression
874+
return expression, nil
875+
}
872876
out, err := Evaluate(env, expression, variableMap)
873877
if err != nil {
874878
variableMap[k] = ""
@@ -915,6 +919,11 @@ func isPlainLiteral(expr string, variableMap map[string]interface{}) bool {
915919
if _, exists := variableMap[expr]; exists {
916920
return false
917921
}
922+
// Base64/JWT 常量常包含 +、/、= 或 .,这些字符在 CEL 中也是语法符号。
923+
// 先识别编码值,避免把密钥和令牌误当成表达式编译。
924+
if isEncodedLiteral(expr) {
925+
return true
926+
}
918927
// 含 CEL 语法特征的需要走 CEL 编译
919928
for _, c := range expr {
920929
switch c {
@@ -925,6 +934,35 @@ func isPlainLiteral(expr string, variableMap map[string]interface{}) bool {
925934
return true
926935
}
927936

937+
func isEncodedLiteral(value string) bool {
938+
if strings.Count(value, ".") == 2 {
939+
parts := strings.Split(value, ".")
940+
for _, part := range parts {
941+
if part == "" || strings.IndexFunc(part, func(r rune) bool {
942+
return !isASCIIAlphaNumeric(r) && r != '-' && r != '_'
943+
}) >= 0 {
944+
return false
945+
}
946+
}
947+
return true
948+
}
949+
950+
if len(value) < 4 || len(value)%4 != 0 {
951+
return false
952+
}
953+
padding := strings.TrimRight(value, "=")
954+
if len(value)-len(padding) > 2 {
955+
return false
956+
}
957+
return strings.IndexFunc(padding, func(r rune) bool {
958+
return !isASCIIAlphaNumeric(r) && r != '+' && r != '/'
959+
}) < 0
960+
}
961+
962+
func isASCIIAlphaNumeric(r rune) bool {
963+
return r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9'
964+
}
965+
928966
// CheckInfoPoc 检查POC信息并返回别名
929967
func CheckInfoPoc(infostr string) string {
930968
for _, poc := range fingerprint.PocDatas {

webscan/lib/poc_executor_test.go

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -608,16 +608,16 @@ func stringMatrixEqual(a, b [][]string) bool {
608608

609609
func TestBuildVulnDetails(t *testing.T) {
610610
tests := []struct {
611-
name string
612-
pocDef *Poc
613-
vulName string
614-
params StrMap
615-
wantKeys []string
616-
wantNoKeys []string
617-
wantVulnType string
618-
wantVulnName string
619-
wantParamVal string
620-
wantParamKey string
611+
name string
612+
pocDef *Poc
613+
vulName string
614+
params StrMap
615+
wantKeys []string
616+
wantNoKeys []string
617+
wantVulnType string
618+
wantVulnName string
619+
wantParamVal string
620+
wantParamKey string
621621
}{
622622
{
623623
name: "最小Poc只有Name",
@@ -647,15 +647,15 @@ func TestBuildVulnDetails(t *testing.T) {
647647
wantVulnName: "Full Vuln",
648648
},
649649
{
650-
name: "有params则details含parameters字段",
651-
pocDef: &Poc{Name: "poc-yaml-params"},
650+
name: "有params则details含parameters字段",
651+
pocDef: &Poc{Name: "poc-yaml-params"},
652652
vulName: "Params Vuln",
653653
params: StrMap{
654654
{Key: "user", Value: "admin"},
655655
{Key: "pass", Value: "123456"},
656656
},
657-
wantKeys: []string{"vulnerability_type", "vulnerability_name", "parameters"},
658-
wantNoKeys: []string{"author"},
657+
wantKeys: []string{"vulnerability_type", "vulnerability_name", "parameters"},
658+
wantNoKeys: []string{"author"},
659659
wantParamKey: "user",
660660
wantParamVal: "admin",
661661
},
@@ -865,3 +865,33 @@ func TestCollectVarDeclarations(t *testing.T) {
865865
}
866866
})
867867
}
868+
869+
func TestEvalSetTreatsEncodedValuesAsLiterals(t *testing.T) {
870+
env := GetBaseEnv()
871+
tests := []string{
872+
"fsHspZw/92PrS3XrPW+vxw==",
873+
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyJ9.feetKmWoPnMkAebjkNnyuKo6c21_hzTgu0dfNqbdpZQ",
874+
}
875+
876+
for _, value := range tests {
877+
variables := map[string]interface{}{}
878+
got, err := evalset(env, variables, "token", value)
879+
if err != nil {
880+
t.Fatalf("evalset(%q) error = %v", value, err)
881+
}
882+
if got != value || variables["token"] != value {
883+
t.Fatalf("evalset(%q) = %q, stored %v", value, got, variables["token"])
884+
}
885+
}
886+
}
887+
888+
func TestEvalSetStillEvaluatesExpressions(t *testing.T) {
889+
variables := map[string]interface{}{}
890+
got, err := evalset(GetBaseEnv(), variables, "token", "randomLowercase(6)")
891+
if err != nil {
892+
t.Fatal(err)
893+
}
894+
if len(got) != 6 {
895+
t.Fatalf("randomLowercase result length = %d, want 6", len(got))
896+
}
897+
}

webscan/pocs/ecology-hrmcareerapplyperview-sqli.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ info:
1212
created: 2025/06/11
1313

1414
set:
15-
randstr: randLowercase(6)
15+
randstr: randomLowercase(6)
1616
rules:
1717
r0:
1818
request:

0 commit comments

Comments
 (0)