package sqlserver import ( "bytes" "encoding/binary" "strconv" osm "git.loafle.net/overflow/service_matcher-go" ) const ( HEADER_TYPE_PRELOGIN uint8 = 0x12 HEADER_TYPE_RESPONSE uint8 = 0x4 PL_OPTION_TOKEN_VERSION uint8 = 0x00 PL_OPTION_TOKEN_ENCRYPTION uint8 = 0x01 PL_OPTION_TOKEN_TRACEID uint8 = 0x05 PL_OPTION_TOKEN_TERMINATOR uint8 = 0xff ENCRYPT_OFF string = "Encryption is available but off." ENCRYPT_ON string = "Encryption is available and on." ENCRYPT_NOT_SUP string = "Encryption is not available." ENCRYPT_REQ string = "Encryption is required." ) type PreloginMsg struct { VersionToken uint8 VersionOffset uint16 VersionLength uint16 EncryptionToken uint8 EncryptionOffset uint16 EncryptionLength uint16 TraceIdToken uint8 TraceIdOffset uint16 TraceIdLength uint16 Terminator uint8 Options [7]uint8 TraceId [36]uint8 } type mssql struct { Type_ uint8 Status uint8 Length uint16 Channel uint16 PacketNum uint8 Window uint8 Prelogin PreloginMsg } type PreloginResponse struct { Msg [256]uint8 } type mssqlResponse struct { Type_ uint8 Status uint8 Length uint16 Channel uint16 PacketNum uint8 Window uint8 PreLoginResp PreloginResponse } type SQLServerMatcher struct { osm.Matchers isSSL bool } func (m *SQLServerMatcher) Key() string { return "SQLSERVER" } func (m *SQLServerMatcher) Type() string { return "DATABASE" } func (m *SQLServerMatcher) Vendor(matchCtx *osm.MatchCtx) string { return "MicroSoft" } func (m *SQLServerMatcher) Version(matchCtx *osm.MatchCtx) string { return "UNKNOWN" } func (m *SQLServerMatcher) OsType(matchCtx *osm.MatchCtx) string { return "UNKNOWN" } func (m *SQLServerMatcher) OsVersion(matchCtx *osm.MatchCtx) string { return "UNKNOWN" } func (m *SQLServerMatcher) Name(matchCtx *osm.MatchCtx) string { if m.isSSL { return "SQL Server (SSL)" } return "SQL Server" } func (m *SQLServerMatcher) IsPrePacket() bool { return false } func (m *SQLServerMatcher) HasResponse(matchCtx *osm.MatchCtx, index int) bool { return true } func (m *SQLServerMatcher) IsError(matchCtx *osm.MatchCtx, index int, packet *osm.Packet) bool { return false } func (m *SQLServerMatcher) Match(matchCtx *osm.MatchCtx, index int, packet *osm.Packet) error { if packet == nil { return osm.NoPacketReceivedError() } reader := new(bytes.Buffer) reader.Write(packet.Buffer) res := mssqlResponse{} if err := binary.Read(reader, binary.BigEndian, &m); err != nil { return osm.NotMatchedError() } if res.Type_ != HEADER_TYPE_RESPONSE { return osm.NotMatchedError() } if res.Length != uint16(packet.Len) { return osm.NotMatchedError() } switch res.PreLoginResp.Msg[res.Length-9 : res.Length-8][0] { case 0: return nil case 1: matchCtx.SetAttribute("isSSL", strconv.FormatBool(true)) return nil case 2: return nil case 3: matchCtx.SetAttribute("isSSL", strconv.FormatBool(true)) return nil default: return osm.NotMatchedError() } return osm.NotMatchedError() } func NewMatcher() osm.Matcher { mm := &SQLServerMatcher{} tempBuf := new(bytes.Buffer) binary.Write(tempBuf, binary.BigEndian, mssql{}) m := mssql{ Type_: HEADER_TYPE_PRELOGIN, Status: 0x01, Length: uint16(len(tempBuf.Bytes())), Channel: 0, PacketNum: 0, Window: 0, Prelogin: PreloginMsg{ VersionToken: PL_OPTION_TOKEN_VERSION, VersionOffset: 0x0010, VersionLength: 0x0006, EncryptionToken: PL_OPTION_TOKEN_ENCRYPTION, EncryptionOffset: 0x0016, EncryptionLength: 0x0001, TraceIdToken: PL_OPTION_TOKEN_TRACEID, TraceIdOffset: 0x0017, TraceIdLength: 0x0024, Terminator: PL_OPTION_TOKEN_TERMINATOR, }, } writer := new(bytes.Buffer) binary.Write(writer, binary.BigEndian, m) mm.AddPacket(osm.NewPacket(writer.Bytes(), writer.Len())) return mm }