
项目备份地址
https://github.dev/Sec-Fork/JNDIScan-1
main.go 分析




- 先打印了logo
core.PrintLogo(config.GetAuthors())
package coreimport "fmt"func PrintLogo(authors []interface{}) {template := " ___ ______ _________ \n" +" / / | / / __ \\/ _/ ___/_________ _____ \n" +" __ / / |/ / / / // / \\__ \\/ ___/ __ `/ __ \\\n" +"/ /_/ / /| / /_/ // / ___/ / /__/ /_/ / / / /\n" +"\\____/_/ |_/_____/___//____/\\___/\\__,_/_/ /_/ \n" +" coded by %s"logo := fmt.Sprintf(template, authors...)fmt.Println(logo)}
package configfunc GetAuthors() []interface{} {return []interface{}{"4ra1n",}}
- 在对传入的参数进行解析
- 初始化定义的输出结果的参数
ldap.go start fake reverse server分析
主程序中
go core.StartFakeServer(&ResultChan)//启动一个goroutine启动反连平台
启动函数

数据处理函数
func acceptProcess(conn *net.Conn) {buf := make([]byte, 1024)num, err := (*conn).Read(buf)if err != nil {log.Error("accept data reading err: %s", err)_ = (*conn).Close()return}hexStr := fmt.Sprintf("%x", buf[:num])// LDAP Protocol// https://ldap.com/ldapv3-wire-protocol-reference-bindif "300c020101600702010304008000" == hexStr {data := []byte{0x30, 0x0c, 0x02, 0x01, 0x01, 0x61, 0x07,0x0a, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00,}_, _ = (*conn).Write(data)_, _ = (*conn).Read(buf)length := buf[8]pathBytes := bytes.Buffer{}for i := 1; i <= int(length); i++ {temp := []byte{buf[8+i]}pathBytes.Write(temp)}path := pathBytes.String()res := &model.Result{Host: (*conn).RemoteAddr().String(),Name: "LDAP",Finger: hexStr,Path: path,}ResultChan <- res_ = (*conn).Close()return}// RMI Protocolif checkRMI(buf) {data := []byte{0x4e, 0x00, 0x09, 0x31, 0x32,0x37, 0x2e, 0x30, 0x2e, 0x30,0x2e, 0x31, 0x00, 0x00, 0xc4, 0x12,}_, _ = (*conn).Write(data)_, _ = (*conn).Read(buf)_, _ = (*conn).Write([]byte{})_, _ = (*conn).Read(buf)var dataList []byteflag := falsefor i := len(buf) - 1; i >= 0; i-- {if buf[i] != 0x00 || flag {flag = truedataList = append(dataList, buf[i])}}var j intfor i := 0; i < len(dataList); i++ {if int(dataList[i]) == i {j = i}}temp := dataList[0:j]pathBytes := &bytes.Buffer{}for i := len(temp) - 1; i >= 0; i-- {pathBytes.Write([]byte{dataList[i]})}res := &model.Result{Host: (*conn).RemoteAddr().String(),Name: "RMI",Finger: fmt.Sprintf("%x", buf[0:7]),Path: pathBytes.String(),}ResultChan <- res_ = (*conn).Close()return}_ = (*conn).Close()return}func checkRMI(data []byte) bool {if data[0] == 0x4a &&data[1] == 0x52 &&data[2] == 0x4d &&data[3] == 0x49 {if data[4] != 0x00 {return false}if data[5] != 0x01 && data[5] != 0x02 {return false}if data[6] != 0x4b &&data[6] != 0x4c &&data[6] != 0x4d {return false}lastData := data[7:]for _, v := range lastData {if v != 0x00 {return false}}return true}return false}
总结而言,就是匹配数据包中的LDAP和RMI的特殊指纹
输出文件分析
主程序:
go core.StartOutput(&RenderChan)
package coreimport ("github.com/EmYiQing/JNDIScan/model""io/ioutil""sync")var (resultList []*model.Resultlock sync.Mutex)func StartOutput(renderChan *chan *model.Result) {go listenData(renderChan)}func listenData(renderChan *chan *model.Result) {for {select {case res := <-*renderChan:lock.Lock()resultList = append(resultList, res)data := RenderHtml(resultList)_ = ioutil.WriteFile("result.html", data, 0666)lock.Unlock()}}}
输出已经定义好的规格的result.html文件
package coreimport ("bytes""fmt""github.com/EmYiQing/JNDIScan/config""github.com/EmYiQing/JNDIScan/model")func RenderHtml(resultList []*model.Result) []byte {if len(resultList) == 0 {return []byte("no result")}data := bytes.Buffer{}data.Write([]byte(config.TemplatePrefix))for i := 1; i < len(resultList)+1; i++ {data.Write([]byte(fmt.Sprintf("<tr>\n "+"<th scope=\"row\">%d</th>\n "+"<td>%s</td>\n "+"<td><span class=\"badge badge-danger\">%s</span></td>\n "+"<td><span class=\"badge badge-warning\">%s</span></td>\n "+"<td><span class=\"badge badge-success\">%s</span></td>\n "+"</tr>", i, (resultList[i-1]).Host,(resultList[i-1]).Name,(resultList[i-1]).Finger,(resultList[i-1]).Path)))}data.Write([]byte(config.TemplateSuffix))return data.Bytes()}
接收传输的数据
主程序
go startApp()
func startApp() {for {select {case res := <-ResultChan:info := fmt.Sprintf("%s->%s", res.Name, res.Host)log.Info(info)data := &model.Result{Host: res.Host,Name: res.Name,Finger: res.Finger,Path: res.Path,}RenderChan <- data}}}
打印成功的payload
主程序
core.PrintPayload()
func PrintPayload() {time.Sleep(time.Second * 3)ipList := util.GetLocalIPs()exIP := util.GetExternalIP()if exIP != "" {ipList = append(ipList, exIP)}port := config.PortborderLen := 23max := 0for i := 0; i < len(ipList); i++ {if len(ipList[i]) > max {max = len(ipList[i])}}borderLen += max + len(strconv.Itoa(port)) + 2fmt.Print("|")for i := 0; i < borderLen; i++ {fmt.Print("-")}fmt.Println("|")for i := 0; i < len(ipList); i++ {tempLen := 18fmt.Print("|--Payload: ldap://")tempLen += len(ipList[i])fmt.Print(ipList[i])tempLen += 1fmt.Print(":")tempLen += len(strconv.Itoa(port))fmt.Print(strconv.Itoa(port))num := borderLen - tempLenfor j := 0; j < num; j++ {fmt.Print("-")}fmt.Println("|")}for i := 0; i < len(ipList); i++ {tempLen := 17fmt.Print("|--Payload: rmi://")tempLen += len(ipList[i])fmt.Print(ipList[i])tempLen += 1fmt.Print(":")tempLen += len(strconv.Itoa(port))fmt.Print(strconv.Itoa(port))tempLen += 4fmt.Print("/xxx")num := borderLen - tempLenfor j := 0; j < num; j++ {fmt.Print("-")}fmt.Println("|")}fmt.Print("|")for i := 0; i < borderLen; i++ {fmt.Print("-")}fmt.Println("|")}
优雅的退出程序
func wait() {sign := make(chan os.Signal, 1)done := make(chan bool, 1)signal.Notify(sign, syscall.SIGINT, syscall.SIGTERM)go func() {sig := <-signfmt.Println()fmt.Println(sig)done <- true}()<-done}
