ing
This commit is contained in:
151
matcher/mysql/mysql.go
Normal file
151
matcher/mysql/mysql.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"git.loafle.net/overflow/overflow_discovery/match/packet"
|
||||
"git.loafle.net/overflow/overflow_discovery/model/scaninfo"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type PacketSize struct {
|
||||
PacketLength [3]byte
|
||||
PacketNumber byte
|
||||
}
|
||||
|
||||
type mySql struct {
|
||||
Payload PacketSize
|
||||
Protocol byte
|
||||
Version [256]byte
|
||||
|
||||
TreadId uint32
|
||||
Salt1 [9]byte
|
||||
ServerCapa uint16
|
||||
ServerLang uint8
|
||||
ServerStat uint16
|
||||
ExtServerCapa uint16
|
||||
AuthPlugLen uint8
|
||||
_ [10]uint8
|
||||
Salt2 [13]uint8
|
||||
AuthPlugName [64]uint8
|
||||
}
|
||||
|
||||
type MySqlMatcher struct {
|
||||
packets []*packet.Packet
|
||||
version string
|
||||
isErrResp bool
|
||||
errCode int
|
||||
errMsg string
|
||||
isSSL bool
|
||||
}
|
||||
|
||||
func NewMySqlMatcher() *MySqlMatcher {
|
||||
return &MySqlMatcher{}
|
||||
}
|
||||
|
||||
func (t *MySqlMatcher) ServiceName() string {
|
||||
if t.isErrResp {
|
||||
return "MySQL" + "(Err-" + strconv.Itoa(t.errCode) + " : " + t.errMsg + ")"
|
||||
}
|
||||
if t.isSSL {
|
||||
return "MySQL" + "-" + t.version + "(SSL)"
|
||||
}
|
||||
return "MySQL" + "(" + t.version + ")"
|
||||
}
|
||||
|
||||
func (t *MySqlMatcher) PacketCount() int {
|
||||
return len(t.packets)
|
||||
}
|
||||
|
||||
func (t *MySqlMatcher) Packet(index int) *packet.Packet {
|
||||
return t.packets[index]
|
||||
}
|
||||
|
||||
func (t *MySqlMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *MySqlMatcher) HasResponse(index int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *MySqlMatcher) IsPrePacket() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (t *MySqlMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
|
||||
|
||||
if packet == nil || len(packet.Buffer) <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
r := new(bytes.Buffer)
|
||||
r.Write(packet.Buffer)
|
||||
|
||||
m := mySql{}
|
||||
if err := binary.Read(r, binary.LittleEndian, &m); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(m.Payload.PacketLength[:])
|
||||
packetLen, _ := binary.ReadUvarint(buf)
|
||||
|
||||
if packetLen != uint64(packet.Len-4) {
|
||||
return false
|
||||
}
|
||||
|
||||
if m.Protocol == 0xff {
|
||||
//MySQL error response
|
||||
var code [2]uint8
|
||||
copy(code[:], m.Version[:2])
|
||||
|
||||
var msg [256]uint8
|
||||
copy(msg[:], m.Version[2:])
|
||||
|
||||
errCode := binary.LittleEndian.Uint16(code[:])
|
||||
if errCode < 1000 || errCode > 1727 {
|
||||
return false
|
||||
}
|
||||
errMsg := bytes.Trim(msg[:], "\x00")
|
||||
|
||||
t.isErrResp = true
|
||||
t.errCode = int(errCode)
|
||||
t.errMsg = string(errMsg)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if m.Protocol != 10 && m.Protocol != 9 {
|
||||
return false
|
||||
}
|
||||
|
||||
t.checkSSL(packet)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (t *MySqlMatcher) checkSSL(packet *packet.Packet) {
|
||||
|
||||
temp := make([]byte, packet.Len)
|
||||
r := new(bytes.Buffer)
|
||||
r.Write(packet.Buffer)
|
||||
|
||||
if err := binary.Read(r, binary.LittleEndian, &temp); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.version = strings.Split(string(packet.Buffer)[5:packet.Len], "\x00")[0]
|
||||
versionLen := len(t.version) + 1
|
||||
data := binary.LittleEndian.Uint16(temp[18+versionLen : 20+versionLen])
|
||||
s := fmt.Sprintf("%b", data)
|
||||
|
||||
for i, b := range s {
|
||||
if i == 4 {
|
||||
if b == 49 {
|
||||
t.isSSL = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
71
matcher/mysql/mysql_test.go
Normal file
71
matcher/mysql/mysql_test.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package mysql
|
||||
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"git.loafle.net/overflow/overflow_discovery/match/packet"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMySql(t *testing.T) {
|
||||
|
||||
m := NewMySqlMatcher()
|
||||
|
||||
/*
|
||||
192.168.1.103:3306 - normal
|
||||
192.168.1.105:8306 - ssl
|
||||
192.168.1.203:3306 - mysql with error code
|
||||
*/
|
||||
conn, _ := net.Dial("tcp", "192.168.1.15:33068")
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
bytes := make([]byte, 1024)
|
||||
n, _ := conn.Read(bytes)
|
||||
p := packet.NewPacket(bytes, n)
|
||||
|
||||
if m.Match(0, p, nil) {
|
||||
t.Log(m.ServiceName())
|
||||
return
|
||||
}
|
||||
|
||||
t.Error("MySQL not found")
|
||||
|
||||
}
|
||||
|
||||
func TestCassandraTLS(t *testing.T) {
|
||||
|
||||
m := NewMySqlMatcher()
|
||||
|
||||
conn, err := tls.Dial(
|
||||
"tcp",
|
||||
"192.168.1.105:8306",
|
||||
&tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "192.168.1.105",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
for i := 0; i < m.PacketCount(); i++ {
|
||||
|
||||
pack := m.Packet(i)
|
||||
conn.Write(pack.Buffer)
|
||||
bytes := make([]byte, 1024)
|
||||
n, _ := conn.Read(bytes)
|
||||
p := packet.NewPacket(bytes, n)
|
||||
|
||||
if m.Match(i, p, nil) {
|
||||
t.Log(m.ServiceName())
|
||||
return
|
||||
}
|
||||
|
||||
t.Error("MySQL not found")
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user