commit eb02693cf59f020e6a2b7506b41b3bbd3851abe4 Author: jackdaw@loafle.com Date: Mon Apr 10 20:14:12 2017 +0900 . diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e2ebe9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,61 @@ +# Created by .ignore support plugin (hsz.mobi) +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +### Go template +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + diff --git a/matcher/activedirectory/activedirectory.go b/matcher/activedirectory/activedirectory.go new file mode 100644 index 0000000..88b45db --- /dev/null +++ b/matcher/activedirectory/activedirectory.go @@ -0,0 +1,342 @@ +package activedirectory + +import ( + "bytes" + "encoding/binary" + + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + AD_MESSAGE_ID = 0x99 + AD_MESSAGE_ID_QUIT = 0x89 + + LDAP_VERSION3 = 3 + + LDAP_SUCCESS = 0x00 + + LDAP_REQ_BIND = 0x60 + LDAP_RES_SEARCH_ENTRY = 0x64 + + LDAP_REQ_UNBIND = 0x42 + LDAP_REQ_SEARCH = 0x63 + + LDAP_SCOPE_BASE = 0x00 + LDAP_DEREF_NEVER = 0x00 + LDAP_FILTER_PRESENT = 0x87 + + LDAP_RES_BIND = 0x61 + + LDAP_AUTH_SIMPLE = 0x80 + + AD_TYPE_STR = "supportedCapabilities" +) + +type AD_SENDaaa struct { + DefaultCode uint8 + PackLenFlag uint8 + PacketLen uint32 + + NextType1 uint8 + NextTypeLength1 uint8 + + MessageId uint32 + + ProtocolOp uint8 + PtLenFlag uint8 + PtPacketLen uint32 + NextType2 uint8 + NextTypeLength2 uint8 + + Version uint8 + + NextType3 uint8 + NextTypeLength3 uint8 + Auth uint8 + AuthLength uint8 +} + +type AD_SEND struct { + DefaultCode uint8 + PackLenFlag uint8 + + PacketLen uint32 + + NextType1 uint8 + NextType1Len uint8 + + MessageId uint32 + + ProtocolOp uint8 + + PtPackLenFlag uint8 + PtPacketLen uint32 + + NextType2 uint8 + NextType2Len uint8 + NextType3 uint8 + NextType3Len uint8 + + Scope uint8 + + NextType4 uint8 + NextType4Len uint8 + + DerefAliases uint8 + + NextType5 uint8 + NextType5Len uint8 + + SizeLimit uint8 + + NextType6 uint8 + NextType6Len uint8 + + TimeLimit uint8 + + NextType7 uint8 + NextType7Len uint8 + + TypesOnly uint8 + + Filter1 uint8 + PresentLen uint8 + + Present [11]byte + + DefaultCode2 uint8 + Pack2LenFlag uint8 + + Packet2Len uint32 + + UnknwonCode8 uint8 + ItemLength uint8 + + AttributeDescription [21]byte +} + +type AD_QUIT struct { + DefaultCode uint8 + PackLenFlag uint8 + + PacketLength uint32 + + NextType1 uint8 + NextTypeLength1 uint8 + + MessageId uint32 + + ProtocolOp uint8 + + PtLenFlag uint8 + PtPacketLen uint32 +} + +type AD_RECV struct { + DefaultCode uint8 + PackLenFlag uint8 + + PacketLength uint32 + + NextType1 uint8 + NextType1Len uint8 + + MessageId uint16 + + ProtocolOp uint8 + + PtPackLenFlag uint8 + PtPacketLen uint32 + + NextType2 uint8 + NextType2Len uint8 + + UnknwonCode21 uint8 + UnknwonCode22 uint8 + UnknwonCode23 uint8 + UnknwonCode24 uint8 + UnknwonCode25 uint8 + UnknwonCode26 uint8 + + UnknwonCode31 uint8 + UnknwonCode32 uint8 + UnknwonCode33 uint8 + UnknwonCode34 uint8 + UnknwonCode35 uint8 + UnknwonCode36 uint8 + UnknwonCode37 uint8 + + TypeLength uint8 +} + +type ActiveDirectoryMatcher struct { + sendPackets []*packet.Packet +} + +func (ad *ActiveDirectoryMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + buf := new(bytes.Buffer) + buf.Write(packet.Buffer) + + adRecv := AD_RECV{} + + binary.Read(buf, binary.BigEndian, &adRecv) + + if adRecv.MessageId != AD_MESSAGE_ID { + return false + } + + if adRecv.ProtocolOp != LDAP_RES_SEARCH_ENTRY { + return false + } + + ///AD_TYPE_STR + + // + //if(packet->readCount_ < sizeof(AD_RECV) + recv->typeLength) { + // return false; + //} + + //char* type = new char[recv->typeLength]; + //memcpy(type, packet->buffer_+sizeof(AD_RECV), recv->typeLength); + //std::string typeStr = type; + // + //delete[] type; + //if(typeStr.compare(AD_TYPE_STR) != 0) { + //return false; + //} + + return true +} + +func (ad *ActiveDirectoryMatcher) PacketCount() int { + return len(ad.sendPackets) +} +func (ad *ActiveDirectoryMatcher) Packet(index int) *packet.Packet { + return ad.sendPackets[index] +} +func (ad *ActiveDirectoryMatcher) ServiceName() string { + return "ActiveDirectory" +} + +func (ad *ActiveDirectoryMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} +func (ad *ActiveDirectoryMatcher) IsNoResponse(index int) bool { + + if index == 1 { + return true + } + + return false +} + +func (ad *ActiveDirectoryMatcher) IsPrePacket() bool { + return false +} + +func NewActiveDirectoryMatcher() *ActiveDirectoryMatcher { + + ls := AD_SEND{ + DefaultCode: 0x30, + PackLenFlag: 0x84, + + PacketLen: 0x47, + + NextType1: 0x02, + NextType1Len: 0x04, + + MessageId: AD_MESSAGE_ID, + + ProtocolOp: LDAP_REQ_SEARCH, + + PtPackLenFlag: 0x84, + PtPacketLen: 0x3b, + + NextType2: 0x04, + NextType2Len: 0x00, + NextType3: 0x0a, + NextType3Len: 0x01, + + Scope: LDAP_SCOPE_BASE, + + NextType4: 0x0a, + NextType4Len: 0x01, + + DerefAliases: LDAP_DEREF_NEVER, + + NextType5: 0x02, + NextType5Len: 0x01, + + SizeLimit: 0, + + NextType6: 0x02, + NextType6Len: 0x01, + + TimeLimit: 0x78, + + NextType7: 0x01, + NextType7Len: 0x01, + + TypesOnly: 0, + + Filter1: LDAP_FILTER_PRESENT, + PresentLen: 0x0b, + + //Present :0000, + + DefaultCode2: 0x30, + Pack2LenFlag: 0x84, + + Packet2Len: 0x17, + + UnknwonCode8: 0x04, + ItemLength: 0x15, + + //AttributeDescription:, + } + + copy(ls.Present[:], "objectclass") + copy(ls.AttributeDescription[:], AD_TYPE_STR) + + mCache := new(bytes.Buffer) + binary.Write(mCache, binary.BigEndian, ls) + + sendByte1 := mCache.Bytes() + + adm := ActiveDirectoryMatcher{ + //sendPackets: make([][]byte, 2), + } + + pp := packet.NewPacket(sendByte1, len(sendByte1)) + + adm.sendPackets = append(adm.sendPackets, pp) + + aq := AD_QUIT{ + DefaultCode: 0x30, + PackLenFlag: 0x84, + PacketLength: 0x0c, + NextType1: 0x02, + NextTypeLength1: 0x04, + MessageId: AD_MESSAGE_ID_QUIT, + ProtocolOp: LDAP_REQ_UNBIND, + PtLenFlag: 0x84, + PtPacketLen: 0x00, + } + + lqBuffer := new(bytes.Buffer) + binary.Write(lqBuffer, binary.BigEndian, aq) + + quBytes := lqBuffer.Bytes() + + pp2 := packet.NewPacket(quBytes, len(quBytes)) + + adm.sendPackets = append(adm.sendPackets, pp2) + + return &adm +} diff --git a/matcher/activedirectory/activedirectory_test.go b/matcher/activedirectory/activedirectory_test.go new file mode 100644 index 0000000..db318a1 --- /dev/null +++ b/matcher/activedirectory/activedirectory_test.go @@ -0,0 +1,77 @@ +package activedirectory + +import ( + "crypto/tls" + "net" + "testing" +) + +func TestADNor(t *testing.T) { + client, err := net.Dial("tcp", "192.168.1.1:389") + + if err != nil { + t.Log(err) + } + + defer client.Close() + + dDRun(client, t) +} + +func TestADTLS(t *testing.T) { + conn, err := tls.Dial( + "tcp", + "192.168.1.1:636", + &tls.Config{ + InsecureSkipVerify: true, + ServerName: "192.168.1.1", + }, + ) + + if err != nil { + t.Log(err) + return + } + + defer conn.Close() + + dDRun(conn, t) +} + +func dDRun(client net.Conn, t *testing.T) { + + //lm := NewActiveDirectoryMatcher() + // + //port := types.NewPort("389", types.NewHost("192.168.1.1"), types.TYPE_TCP) + // + //var ipport string + //ipport = port.Host.Ip + ":" + string(port.Port) + // + //fmt.Println(ipport) + // + //fmt.Println(lm.PacketCount()) + // + //for ii := 0; ii < lm.PacketCount(); ii++ { + // + // pack := lm.Packet(ii) + // + // fmt.Println(pack) + // + // client.Write(pack.Buffer) + // + // bytes := make([]byte, 1024) + // + // read, _ := client.Read(bytes) + // + // fmt.Println(bytes) + // + // b := lm.Match(ii, packet.NewPacket(bytes, read), scanInfo) + // + // if b { + // fmt.Println("Good") + // } + // + //} + // + //t.Log(scanInfo) +} diff --git a/matcher/cassandra/cassandra.go b/matcher/cassandra/cassandra.go new file mode 100644 index 0000000..0178684 --- /dev/null +++ b/matcher/cassandra/cassandra.go @@ -0,0 +1,105 @@ +package cassandra + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + COMPRESSION = "COMPRESSION" + CQL_VERSION = "CQL_VERSION" +) + +type cassandra struct { + Version uint8 + Flags uint8 + Stream uint16 + Opcode uint8 + Length uint32 +} + +type CassandraMatcher struct { + packets []*packet.Packet +} + +func NewCassandraMatcher() *CassandraMatcher { + + cassMatcher := &CassandraMatcher{} + c := cassandra{ + Version: 4, + Flags: 0, + Stream: 0, + Opcode: 5, + Length: 0, + } + writer := new(bytes.Buffer) + binary.Write(writer, binary.LittleEndian, c) + + cassMatcher.packets = append(cassMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len())) + + return cassMatcher +} + +func (t *CassandraMatcher) ServiceName() string { + return "Cassandra" +} + +func (t *CassandraMatcher) PacketCount() int { + return len(t.packets) +} +func (t *CassandraMatcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *CassandraMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *CassandraMatcher) IsNoResponse(index int) bool { + return false +} + +func (t *CassandraMatcher) IsPrePacket() bool { + return false +} + +func (t *CassandraMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + reader := new(bytes.Buffer) + reader.Write(packet.Buffer) + + c := cassandra{} + if err := binary.Read(reader, binary.BigEndian, &c); err != nil { + return false + } + if c.Version != 0x84 { + return false + } + if c.Flags != 0x00 { + return false + } + if c.Stream != 0x00 { + return false + } + if c.Opcode != 0x06 { + return false + } + var itemcount uint16 + + if binary.Read(reader, binary.BigEndian, &itemcount) != nil { + return false + } + + if itemcount != 0 && itemcount != 2 { + return false + } + + return true + +} diff --git a/matcher/cassandra/cassandra_test.go b/matcher/cassandra/cassandra_test.go new file mode 100644 index 0000000..52ade00 --- /dev/null +++ b/matcher/cassandra/cassandra_test.go @@ -0,0 +1,74 @@ +package cassandra + +// +//import ( +// "crypto/tls" +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//func TestCassandra(t *testing.T) { +// +// m := NewCassandraMatcher() +// +// conn, err := net.Dial("tcp", "192.168.1.104:9042") +// if err != nil { +// t.Error(err) +// return +// } +// 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("Cassandra found") +// return +// } +// +// t.Error("Cassandra not found") +// } +// +//} +// +//func TestCassandraTLS(t *testing.T) { +// +// m := NewCassandraMatcher() +// +// conn, err := tls.Dial( +// "tcp", +// "192.168.1.104:9042", +// &tls.Config{ +// InsecureSkipVerify: true, +// ServerName: "192.168.1.104", +// }, +// ) +// 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("Cassandra found") +// return +// } +// +// t.Error("Cassandra not found") +// } +// +//} diff --git a/matcher/dhcp/dhcp.go b/matcher/dhcp/dhcp.go new file mode 100644 index 0000000..97a176b --- /dev/null +++ b/matcher/dhcp/dhcp.go @@ -0,0 +1,188 @@ +package dhcp + +// +//import ( +// "bytes" +// "encoding/binary" +// "fmt" +// log "github.com/cihub/seelog" +// "loafle.com/overflow/commons_go/matcher" +// "net" +// "time" +//) +// +//const ( +// MAGIC_COOKIE uint32 = 0x63825363 +// OPT_CODE_SERVER_IDENTIFIER uint8 = 54 +// OPT_CODE_SUBNET_MASK uint8 = 1 +// OPT_CODE_ROUTER uint8 = 3 +// OPT_CODE_DNS uint8 = 6 +//) +// +//type dhcpDiscover struct { +// MsgType byte +// HwType byte +// HwAddrLen byte +// Hops byte +// Xid uint32 +// Secs uint16 +// BootpFlags uint16 +// ClientIp uint32 +// YourIp uint32 +// NextServerIp uint32 +// RelayAgentIp uint32 +// ClientMacAddr [6]byte +// ClientHwAddrPadding [10]byte +// ServerHostName [64]byte +// BootFileName [128]byte +// MagicCookie uint32 +// Mtype byte +// MtypeLen byte +// MtypeVal byte +// Opts [200]byte +// End byte +// Padding [16]byte +//} +// +//func DiscoverDHCP(zone *types.DiscoveryZone) { +// err := sendDHCPDiscovery() +// if err != nil { +// log.Error(err) +// return +// } +// recvDHCPOffer(zone) +//} +// +//func sendDHCPDiscovery() error { +// dhcp := dhcpDiscover{ +// MsgType: 0x01, +// HwType: 0x01, +// HwAddrLen: 0x06, +// Hops: 0x00, +// Xid: 0x00000000, +// Secs: 0x0000, +// ClientIp: 0x00000000, +// YourIp: 0x00000000, +// NextServerIp: 0x00000000, +// RelayAgentIp: 0x00000000, +// MagicCookie: MAGIC_COOKIE, +// Mtype: 0x35, +// MtypeLen: 0x01, +// MtypeVal: 0x01, +// End: 0xff, +// } +// +// var flag uint16 = 0 +// dhcp.BootpFlags = ^flag // flag = unicast , ^flag = broadcast +// +// //TODO : getting mac addr from zone +// dhcp.ClientMacAddr[0] = 0x50 +// dhcp.ClientMacAddr[1] = 0xe5 +// dhcp.ClientMacAddr[2] = 0x49 +// dhcp.ClientMacAddr[3] = 0x46 +// dhcp.ClientMacAddr[4] = 0x93 +// dhcp.ClientMacAddr[5] = 0x28 +// +// writer := new(bytes.Buffer) +// binary.Write(writer, binary.BigEndian, dhcp) +// conn, err := net.Dial("udp", "255.255.255.255:67") +// if err != nil { +// return err +// } +// conn.Write(writer.Bytes()) +// defer conn.Close() +// +// return nil +//} +// +//func recvDHCPOffer(zone *types.DiscoveryZone) { +// +// socket, err := net.ListenUDP("udp4", &net.UDPAddr{ +// IP: net.IPv4(255, 255, 255, 255), +// Port: 68, +// }) +// if err != nil { +// log.Error(err) +// return +// } +// err = socket.SetDeadline(time.Now().Add(3 * time.Second)) +// if err != nil { +// log.Error(err) +// return +// } +// +// buf := make([]byte, 4096) +// n, _, err := socket.ReadFromUDP(buf) +// if err != nil { +// log.Error(err) +// return +// } +// if n <= 0 { +// log.Error("No DHCP offer.") +// return +// } +// +// offer := dhcpDiscover{} +// +// reader := new(bytes.Buffer) +// reader.Write(buf) +// if err := binary.Read(reader, binary.BigEndian, &offer); err != nil { +// log.Error(err) +// return +// } +// if offer.MagicCookie != MAGIC_COOKIE { +// log.Error("Not a DHCP packet.") +// return +// } +// +// //option searching +// r := new(bytes.Buffer) +// r.Write(offer.Opts[:]) +// +// for i := 0; i < r.Len(); i++ { +// v := r.Next(1)[0] +// +// if v == OPT_CODE_SUBNET_MASK && r.Next(1)[0] == 4 { +// ipStr := byteToIpString(r.Next(4)) +// log.Infof("SUBNET MASK: %s", ipStr) +// } +// +// if v == OPT_CODE_ROUTER && r.Next(1)[0] == 4 { +// ipStr := byteToIpString(r.Next(4)) +// log.Infof("ROUTER: %s", ipStr) +// } +// +// if v == OPT_CODE_DNS { +// len := r.Next(1)[0] +// var dns []string = make([]string, 0) +// var ipStr string +// ipStr = byteToIpString(r.Next(4)) +// dns = append(dns, ipStr) +// if len == 8 { +// ipStr = byteToIpString(r.Next(4)) +// dns = append(dns, ipStr) +// } +// log.Infof("DNS", dns) +// } +// +// if v == OPT_CODE_SERVER_IDENTIFIER && r.Next(1)[0] == 4 { +// ipStr := byteToIpString(r.Next(4)) +// log.Infof("DHCP SERVER: %s", ipStr) +// } +// } +// +//} +// +//func byteToIpString(b []byte) string { +// var ipStr string +// len := len(b) +// for i := 0; i < len; i++ { +// v := b[i] +// ipStr += fmt.Sprintf("%d", v) +// if i < len-1 { +// ipStr += "." +// } +// } +// +// return ipStr +//} diff --git a/matcher/dhcp/dhcp_test.go b/matcher/dhcp/dhcp_test.go new file mode 100644 index 0000000..b1ca4cb --- /dev/null +++ b/matcher/dhcp/dhcp_test.go @@ -0,0 +1,12 @@ +package dhcp + +// +//import ( +// "loafle.com/overflow/collector/core/scan/zone" +// "testing" +//) +// +//func TestDHCP(t *testing.T) { +// zone := zone.NewZone() +// DiscoverDHCP(zone) +//} diff --git a/matcher/dns/dns.go b/matcher/dns/dns.go new file mode 100644 index 0000000..a73cf78 --- /dev/null +++ b/matcher/dns/dns.go @@ -0,0 +1,151 @@ +package dns + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +type Dns_frame_header struct { + Transaction_id uint16 + Flags uint16 + Questions uint16 + Answer_rrs uint16 + Authority_rrs uint16 + Additional_rrs uint16 +} + +type Dns_query_section struct { + Name uint8 + Query_type uint16 + Class_type uint16 +} + +type Dns_authority_section struct { + Name uint8 + Auth_type uint16 + Class_type uint16 + Time_to_live uint32 + Data_length uint16 + Primary_name_server [20]uint8 + Responsible_authority_mailbox [24]uint8 + Serial_number uint32 + Refresh_interval uint32 + Retry_interval uint32 + Expire_limit uint32 + Minium_ttl uint32 +} + +type DNSMatcher struct { + packets []*packet.Packet +} + +func NewDnsMatcher() *DNSMatcher { + + m := &DNSMatcher{} + + header := Dns_frame_header{ + Transaction_id: 0x2a88, + Flags: 0x0100, + Questions: 1, + Answer_rrs: 0, + Authority_rrs: 0, + Additional_rrs: 0, + } + + query := Dns_query_section{ + Name: 0, + Query_type: 1, + Class_type: 1, + } + + buf := new(bytes.Buffer) + binary.Write(buf, binary.BigEndian, header) + binary.Write(buf, binary.BigEndian, query) + + m.packets = append(m.packets, packet.NewPacket(buf.Bytes(), buf.Len())) + + return m +} + +func (t *DNSMatcher) ServiceName() string { + return "DNS" +} + +func (t *DNSMatcher) PacketCount() int { + return len(t.packets) +} +func (t *DNSMatcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *DNSMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *DNSMatcher) IsNoResponse(index int) bool { + return false +} + +func (t *DNSMatcher) IsPrePacket() bool { + return true +} + +func (t *DNSMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + if packet == nil { + return false + } + if packet.Len <= 0 { + return false + } + + reader := new(bytes.Buffer) + reader.Write(packet.Buffer) + + h := Dns_frame_header{} + if err := binary.Read(reader, binary.BigEndian, &h); err != nil { + return false + } + + if h.Transaction_id != 0x2a88 { + return false + } + if h.Flags != 0x8180 && h.Flags != 0x8182 { + return false + } + if h.Questions != 1 { + return false + } + if h.Answer_rrs != 0 { + return false + } + if h.Authority_rrs != 0 && h.Authority_rrs != 1 { + return false + } + if h.Additional_rrs != 0 && h.Additional_rrs != 1 { + return false + } + + q := Dns_query_section{} + if err := binary.Read(reader, binary.BigEndian, &q); err != nil { + return false + } + if q.Name != 0 { + return false + } + if q.Query_type != 1 { + return false + } + if q.Class_type != 1 { + return false + } + + return true +} +func (t *DNSMatcher) IsSend(port int) bool { + if port == 53 { + return true + } + return false +} diff --git a/matcher/dns/dns_test.go b/matcher/dns/dns_test.go new file mode 100644 index 0000000..18cb258 --- /dev/null +++ b/matcher/dns/dns_test.go @@ -0,0 +1,33 @@ +package dns + +//import ( +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//func TestDns(t *testing.T) { +// m := NewDnsMatcher() +// +// conn, _ := net.Dial("udp", "192.168.1.215:53") +// +// defer conn.Close() +// +// for i := 0; i < m.PacketCount(); i++ { +// if m.IsSend(53) != true { +// t.Error("not port") +// } +// 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("dns found") +// return +// } +// +// t.Error("dns not found") +// } +//} diff --git a/matcher/ftp/ftp.go b/matcher/ftp/ftp.go new file mode 100644 index 0000000..df439cd --- /dev/null +++ b/matcher/ftp/ftp.go @@ -0,0 +1,142 @@ +package ftp + +import ( + log "github.com/cihub/seelog" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +// FTP Status codes, defined in RFC 959 +const ( + statusReadyServer = "120" + statusOK = "200" + statusNewConnectOK = "220" + statusSystemNameOK = "215" + statusCloseConnect = "221" + statusUnkownCMD = "202" + statusTlsUseOK = "234" + statusCloseControlConnect = "421" + statusSyntaxErr = "500" + statusParamSyntaxErr = "501" + statusNotUseCMD = "502" + statusIncorrectCMD = "503" + statusTlsNotUse = "534" + statusNeedUserId = "332" +) + +type FTPMatcher struct { + sendPackets []*packet.Packet + isFtps bool +} + +func (ftp *FTPMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + result := false + + if packet == nil || packet.Buffer == nil || packet.Len == 0 { + log.Error("Packet nil") + return result + } + + str := string(packet.Buffer) + //fmt.Println(str) + code := str[:3] + + if index == 0 { + switch code { + case statusNewConnectOK, statusReadyServer: + //fmt.Println(code) + result = true + break + } + } else if index == 1 { + switch code { + case statusSystemNameOK, statusSyntaxErr, statusParamSyntaxErr, statusNotUseCMD: + //fmt.Println(code) + result = true + break + } + } else if index == 2 { + switch code { + case statusIncorrectCMD, statusParamSyntaxErr, statusNotUseCMD, statusNeedUserId: + //fmt.Println(code) + result = true + break + } + } else if index == 3 { + switch code { + case statusCloseConnect, statusSyntaxErr: + //fmt.Println(code) + result = true + break + } + } + + if index == 3 && result == true { + var err error + var isfs bool + + //fmt.Println(info.Port.Host.Ip, info.Port.Port) + + isfs, err = StartCheckFTPS(info.GetIP(), info.GetPort()) + + if isfs && err == nil { + ftp.isFtps = isfs + } else if err != nil { + log.Warn("FTPS Check Error : ", err.Error()) + } + } + + return result +} + +func (ftp *FTPMatcher) PacketCount() int { + return len(ftp.sendPackets) +} + +func (ftp *FTPMatcher) Packet(index int) *packet.Packet { + return ftp.sendPackets[index] +} + +func (ftp *FTPMatcher) ServiceName() string { + re := "" + if ftp.isFtps { + re = "FTPS" + } else { + re = "FTP" + } + return re +} + +func (ftp *FTPMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (ftp *FTPMatcher) IsNoResponse(index int) bool { + return false +} + +func (ftp *FTPMatcher) IsPrePacket() bool { + return true +} + +func NewFTPMatcher() *FTPMatcher { + + ftm := FTPMatcher{} + + sysStr := "SYST\r\n" + systByte := make([]byte, len(sysStr)) + copy(systByte[:], sysStr) + ftm.sendPackets = append(ftm.sendPackets, packet.NewPacket(systByte, len(sysStr))) + + passStr := "PASS \r\n" + passByte := make([]byte, len(passStr)) + copy(passByte[:], passStr) + ftm.sendPackets = append(ftm.sendPackets, packet.NewPacket(passByte, len(passStr))) + + quitStr := "QUIT\r\n" + quitByte := make([]byte, len(quitStr)) + copy(quitByte[:], quitStr) + ftm.sendPackets = append(ftm.sendPackets, packet.NewPacket(quitByte, len(quitStr))) + + return &ftm +} diff --git a/matcher/ftp/ftp_test.go b/matcher/ftp/ftp_test.go new file mode 100644 index 0000000..9f9e55e --- /dev/null +++ b/matcher/ftp/ftp_test.go @@ -0,0 +1,235 @@ +package ftp + +import ( + "fmt" + "testing" + + log "github.com/cihub/seelog" + "loafle.com/overflow/collector/discovery/scan/matcher/packet" + "loafle.com/overflow/collector/discovery/scan/matcher/scaninfo" + "loafle.com/overflow/collector/discovery/types" + "net" +) + +//type FTP struct { +// conn net.Conn +// addr string +// +// reader *bufio.Reader +// writer *bufio.Writer +//} +// +//func (ftp *FTP) Close() { +// ftp.conn.Close() +//} +// +//func Connect(addr string) (*FTP, error) { +// var err error +// var conn net.Conn +// +// if conn, err = net.Dial("tcp", addr); err != nil { +// return nil, err +// } +// +// writer := bufio.NewWriter(conn) +// reader := bufio.NewReader(conn) +// +// obj := &FTP{ +// conn:conn, +// addr:addr, +// reader:reader, +// writer:writer, +// } +// recv, _ := obj.receive() +// +// fmt.Println(recv) +// +// return obj, nil +// +//} +// +//func (ftp *FTP) receive() (string, error) { +// line, err := ftp.receiveLine() +// +// if err != nil { +// return line, err +// } +// +// fmt.Println("len : ", len(line)) +// fmt.Println("line[3] :", line[3]) +// // +// //if (len(line) >= 4) && (line[3] == '-') { +// // closingCode := line[:3] + " " +// // +// // for { +// // str, err := ftp.receiveLine() +// // fmt.Println("str pre: ", str) +// // line = line + str +// // fmt.Println("str after: ", line) +// // if err != nil { +// // return line, err +// // } +// // +// // if len(str) < 4 { +// // fmt.Println("Uncorrectly terminated response") +// // }else { +// // if str[:4] == closingCode { +// // break +// // } +// // } +// // } +// //} +// +// ftp.ReadAndDiscard() +// +// fmt.Println("receive line: ", line) +// return line, err +//} +// +//func (ftp *FTP) ReadAndDiscard() (int, error) { +// var i int +// bufferSize := ftp.reader.Buffered() +// +// for i = 0; i < bufferSize ; i++ { +// if _, err := ftp.reader.ReadByte(); err != nil { +// return i, err +// } +// } +// +// return i, nil +//} +// +//func (ftp *FTP) send(command string, arguments ...interface{}) error { +// +// command = fmt.Sprintf(command) +// command += "\r\n" +// +// if _, err := ftp.writer.WriteString(command); err != nil { +// return err +// } +// +// if err := ftp.writer.Flush(); err != nil { +// return err +// } +// +// return nil +//} +// +//func (ftp *FTP) cmd(expects string, command string, args ...interface{}) (line string, err error) { +// +// if err = ftp.send(command, args); err != nil { +// return +// } +// +// if line, err = ftp.receive(); err != nil { +// return +// } +// +// +// if !strings.HasPrefix(line, expects) { +// err = errors.New(line) +// return +// } +// +// return +//} +// +//func (ftp *FTP) receiveLine() (string, error) { +// line, err := ftp.reader.ReadString('\n') +// +// log.Printf("< %s", line) +// +// return line, err +//} +// +//func (ftp *FTP) Syst() (line string, err error) { +// if err := ftp.send("SYST"); err != nil { +// return "", err +// } +// +// if line, err = ftp.receive(); err != nil { +// return +// } +// +// if !strings.HasPrefix(line, "215") { +// err = errors.New(line) +// return +// } +// +// return strings.SplitN(strings.TrimSpace(line), " ", 2)[1], nil +//} + +//func TestFtp(t *testing.T) { +// var err error +// var ftp *FTP +// //var f *FTPMatcher +// +// if ftp, err = Connect("192.168.1.202:21"); err != nil { +// panic(err) +// } +// +// //f.Match(0, nil,nil) +// ftp.Syst() +// ftp.cmd("503","PASS ") +// ftp.cmd("221","QUIT") +// defer ftp.Close() +//} + +func TestMatchFTP(t *testing.T) { + ftm := NewFTPMatcher() + //fmt.Println(ftm) + //fmt.Println(ftm.sendPackets[0]) + + //log.LoadLogConfig("../../../../../../../../bin/log.xml") + //defer log.Flush() + + port := types.NewPort("21", types.NewHost("192.168.1.202"), types.TYPE_TCP) + info := scaninfo.NewServiceScanInfo(port) + + var ipport string + ipport = port.Host.Ip + ":" + string(port.Port) + + log.Debug(ipport) + + client, _ := net.Dial("tcp", ipport) + + defer client.Close() + + //reader := bufio.NewReader(client) + //writer := bufio.NewWriter(client) + + fmt.Println(ftm.PacketCount()) + //fmt.Println(reader.ReadString('\n')) + + bytes := make([]byte, 512) + + le, _ := client.Read(bytes) + + fmt.Println(bytes) + + b := ftm.Match(0, packet.NewPacket(bytes, le), nil) + + fmt.Println(b) + + for ii := 0; ii < ftm.PacketCount(); ii++ { + pack := ftm.Packet(ii) + + fmt.Println(pack) + + //writer.WriteString(pack) + client.Write(pack.Buffer) + //fmt.Println(reader.ReadString('\n')) + bytes := make([]byte, 512) + + l, _ := client.Read(bytes) + + //fmt.Println(bytes) + + b := ftm.Match(ii+1, packet.NewPacket(bytes, l), info) + + fmt.Println(b) + + } + + fmt.Println("Service Name : ", ftm.ServiceName()) +} diff --git a/matcher/ftp/ftps.go b/matcher/ftp/ftps.go new file mode 100644 index 0000000..ced39ab --- /dev/null +++ b/matcher/ftp/ftps.go @@ -0,0 +1,191 @@ +package ftp + +import ( + "bufio" + "crypto/tls" + "errors" + "fmt" + log "github.com/cihub/seelog" + "net" + "strings" + "time" +) + +// FTP is a Session for file Transfer Protocol +type FTPS struct { + conn net.Conn + addr string + tlsconfig *tls.Config + + reader *bufio.Reader + writer *bufio.Writer + + isFtps bool +} + +func (fs *FTPS) close() { + fs.conn.Close() +} + +func (fs *FTPS) quit() (err error) { + if _, err := fs.cmd(statusCloseConnect, "QUIT"); err != nil { + return err + } + fs.conn.Close() + fs.conn = nil + return nil +} + +func (fs *FTPS) cmd(expects string, cmd string) (line string, err error) { + if err = fs.send(cmd); err != nil { + log.Error("ftps.go cmd send error: ", err) + return "", err + } + + if line, err = fs.receive(); err != nil { + log.Error("ftps.go cmd receive error: ", err) + return line, err + } + + if !strings.HasPrefix(line, expects) { + err = errors.New(line) + return line, err + } + + return line, err +} + +func (fs *FTPS) readAndDiscard() (int, error) { + var i int + bufferSize := fs.reader.Buffered() + + for i = 0; i < bufferSize; i++ { + if _, err := fs.reader.ReadByte(); err != nil { + return i, err + } + } + + return i, nil +} + +func (fs *FTPS) receive() (string, error) { + line, err := fs.reader.ReadString('\n') + //log.Debug("< %s", line) + + if err != nil { + return line, err + } + + fs.readAndDiscard() + //fmt.Println(line) + return line, err +} + +func (fs *FTPS) send(cmd string) (err error) { + + if len(cmd) == 0 { + err = errors.New("command length 0") + } + + cmd = fmt.Sprintf(cmd) + cmd += "\r\n" + + if _, err := fs.writer.WriteString(cmd); err != nil { + return err + } + + if err := fs.writer.Flush(); err != nil { + return err + } + return nil +} + +func (fs *FTPS) authTls(config *tls.Config) error { + if _, err := fs.cmd(statusTlsUseOK, "AUTH TLS"); err != nil { + return err + } + + fs.tlsconfig = config + + fs.conn = tls.Client(fs.conn, config) + fs.writer = bufio.NewWriter(fs.conn) + fs.reader = bufio.NewReader(fs.conn) + + _, err := fs.cmd(statusOK, "PBSZ 0") + + if err != nil { + return err + } + + _, err = fs.cmd(statusOK, "PROT P") + + if err != nil { + return err + } + + return nil +} +func (fs *FTPS) NewFTPSConnect(addr string) (*FTPS, error) { + var err error + var conn net.Conn + + if conn, err = net.Dial("tcp", addr); err != nil { + log.Error("FTPS Socket Fail: ", err.Error()) + return nil, err + } + + err = conn.SetDeadline(time.Now().Add(3 * time.Second)) + if err != nil { + //log.Error("FTPS Socket Fail: ", err.Error()) + return nil, err + } + + writer := bufio.NewWriter(conn) + reader := bufio.NewReader(conn) + + var line string + + obj := &FTPS{ + conn: conn, + addr: addr, + reader: reader, + writer: writer, + } + + line, err = obj.receive() + + if !strings.HasPrefix(line, "220") { + err = errors.New(line) + return nil, err + } + + //log.Debug(line) + + return obj, err +} + +func StartCheckFTPS(ip string, port string) (bool, error) { + + var err error + var fs *FTPS + + addr := ip + ":" + port + //log.Debug("address : " + addr) + + if fs, err = fs.NewFTPSConnect(addr); err != nil { + return false, err + } + + defer fs.close() + + config := &tls.Config{ + InsecureSkipVerify: true, + ClientAuth: tls.RequestClientCert, + } + + if err = fs.authTls(config); err != nil { + return false, err + } + + return true, err +} diff --git a/matcher/ftp/ftps_test.go b/matcher/ftp/ftps_test.go new file mode 100644 index 0000000..6771896 --- /dev/null +++ b/matcher/ftp/ftps_test.go @@ -0,0 +1,13 @@ +package ftp + +import ( + "fmt" + "testing" +) + +func TestStartCheckFTPS(t *testing.T) { + + isFtps, err := StartCheckFTPS("192.168.1.202", "80") + fmt.Println("Result : ", isFtps) + fmt.Println("Error : ", err) +} diff --git a/matcher/http/http.go b/matcher/http/http.go new file mode 100644 index 0000000..5c134d5 --- /dev/null +++ b/matcher/http/http.go @@ -0,0 +1,90 @@ +package http + +import ( + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" + "strings" +) + +type HTTPMatcher struct { + sendPackets []*packet.Packet +} + +func (h *HTTPMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + result := false + + if packet == nil || packet.Buffer == nil || packet.Len == 0 { + return result + } + + str := string(packet.Buffer) + //fmt.Println(str) + elems := strings.Split(str, "\r\n") + + if len(elems) <= 0 { + return result + } + + protocol := (elems[0])[:8] + + httpv0 := strings.Compare(protocol, "HTTP/1.0") + httpv1 := strings.Compare(protocol, "HTTP/1.1") + httpv2 := strings.Compare(protocol, "HTTP/1.2") + + if 0 == httpv0 || 0 == httpv1 || 0 == httpv2 { + result = true + } + + serverName := "Unknown Server" + + for _, valueStr := range elems { + tempElems := strings.Split(valueStr, ":") + + if 0 == strings.Compare(tempElems[0], "Server") { + serverName = tempElems[1] + break + } + } + + strings.Compare(serverName, "Unknown") + //fmt.Println("HTTP Server Name: ", serverName) + + return result +} + +func (h *HTTPMatcher) PacketCount() int { + return len(h.sendPackets) +} + +func (h *HTTPMatcher) Packet(index int) *packet.Packet { + + return h.sendPackets[index] +} + +func (h *HTTPMatcher) ServiceName() string { + return "HTTP" +} + +func (h *HTTPMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (h *HTTPMatcher) IsNoResponse(index int) bool { + return false +} + +func (h *HTTPMatcher) IsPrePacket() bool { + return false +} + +func NewHTTPMatcher() *HTTPMatcher { + + h := HTTPMatcher{} + reqStr := "GET / HTTP/1.1\r\n\r\n" + byte := make([]byte, len(reqStr)) + copy(byte[:], reqStr) + + h.sendPackets = append(h.sendPackets, packet.NewPacket(byte, len(reqStr))) + + return &h +} diff --git a/matcher/http/http_test.go b/matcher/http/http_test.go new file mode 100644 index 0000000..9200536 --- /dev/null +++ b/matcher/http/http_test.go @@ -0,0 +1,49 @@ +package http + +//import ( +// "fmt" +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +//func TestHTTPMatcher_Packet(t *testing.T) { +// hm := NewHTTPMatcher() +// fmt.Println(hm) +// fmt.Println(hm.sendPackets[0]) +// +//} +// +//func TestHTTPMatcher_Match(t *testing.T) { +// fmt.Println("Match") +// +// hm := NewHTTPMatcher() +// +// port := types.NewPort("80", types.NewHost("192.168.1.103"), types.TYPE_TCP) +// +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// //fmt.Println(ipport) +// +// client, _ := net.Dial("tcp", ipport) +// +// defer client.Close() +// +// pack := hm.Packet(0) +// +// //fmt.Println(pack) +// +// //writer.WriteString(pack) +// client.Write(pack.Buffer) +// +// bytes := make([]byte, 512) +// +// l, _ := client.Read(bytes) +// +// //fmt.Println(bytes) +// +// hm.Match(0, packet.NewPacket(bytes, l), nil) +// +//} diff --git a/matcher/http/https_test.go b/matcher/http/https_test.go new file mode 100644 index 0000000..ab4b125 --- /dev/null +++ b/matcher/http/https_test.go @@ -0,0 +1,55 @@ +package http + +//import ( +// "crypto/tls" +// "fmt" +// "loafle.com/overflow/collector/discovery/scan/matcher/packet" +// "log" +// "net" +// "testing" +// "time" +//) +// +//func TestHTTPSMatcher_Match(t *testing.T) { +// netinfo := "192.168.1.1:443" +// dialer := &net.Dialer{ +// Timeout: 5 * time.Second, +// } +// +// conn, err := tls.DialWithDialer( +// dialer, +// "tcp", +// netinfo, +// &tls.Config{ +// InsecureSkipVerify: true, +// ServerName: "192.168.1.103", +// }, +// ) +// +// if err != nil { +// log.Println(err) +// return +// } +// defer conn.Close() +// +// //fmt.Println(conn) +// h := NewHTTPMatcher() +// +// pac := h.Packet(0) +// +// //fmt.Println(pac) +// //fmt.Println(pac.Buffer) +// +// //bytes := make([]byte, 1024) +// +// l, _ := conn.Write(pac.Buffer) +// +// buf := make([]byte, 1024) +// l, _ = conn.Read(buf) +// +// fmt.Println(string(buf)) +// fmt.Println(l) +// is := h.Match(0, packet.NewPacket(buf, l), nil) +// fmt.Println(is) +// +//} diff --git a/matcher/imap/imap.go b/matcher/imap/imap.go new file mode 100644 index 0000000..b7f997a --- /dev/null +++ b/matcher/imap/imap.go @@ -0,0 +1,87 @@ +package imap + +import ( + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + PRE_COMPARE_STR = "* OK" + SEND_COMPARE_STR = "* BYE" +) + +type IMAPMatcher struct { + sendPackets []*packet.Packet +} + +func (i *IMAPMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + switch index { + case 0: + + recvStr := string(packet.Buffer) + + if len(recvStr) < 3 { + return false + } + + compareStr := recvStr[0:4] + + if compareStr == PRE_COMPARE_STR { + return true + } + + case 1: + + recvStr := string(packet.Buffer) + + if len(recvStr) < 5 { + return false + } + + compareStr := recvStr[0:5] + + if compareStr == SEND_COMPARE_STR { + return true + } + + } + + return false +} + +func (i *IMAPMatcher) PacketCount() int { + return len(i.sendPackets) +} +func (i *IMAPMatcher) Packet(index int) *packet.Packet { + return i.sendPackets[index] +} +func (i *IMAPMatcher) ServiceName() string { + return "IMAP" +} + +func (i *IMAPMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} +func (i *IMAPMatcher) IsNoResponse(index int) bool { + + return false +} + +func (i *IMAPMatcher) IsPrePacket() bool { + return true +} + +func NewIMAPMatcher() *IMAPMatcher { + + im := IMAPMatcher{} + + reqStr := "A0001 LOGOUT\r\n" + byte := make([]byte, len(reqStr)) + copy(byte[:], reqStr) + + im.sendPackets = append(im.sendPackets, packet.NewPacket(byte, len(reqStr))) + + return &im + +} diff --git a/matcher/imap/imap_test.go b/matcher/imap/imap_test.go new file mode 100644 index 0000000..c5f8e8c --- /dev/null +++ b/matcher/imap/imap_test.go @@ -0,0 +1,150 @@ +package imap + +// +//import ( +// "crypto/tls" +// "fmt" +// "loafle.com/overflow/collector/core/scan/port" +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "loafle.com/overflow/collector/core/scan/service/matcher/scaninfo" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +//func ImapRun(client net.Conn, t *testing.T) { +// +// lm := NewIMAPMatcher() +// +// port := types.NewPort("143", types.NewHost("192.168.1.215"), types.TYPE_TCP) +// +// scanInfo := types.NewServiceScanInfo(port) +// +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// fmt.Println(ipport) +// //client, _ := net.Dial("tcp", ipport) +// +// //defer client.Close() +// +// bytett := make([]byte, 1024) +// +// rr, _ := client.Read(bytett) +// +// bb := lm.Match(0, packet.NewPacket(bytett, rr), scanInfo) +// +// if bb { +// t.Log("good!") +// } +// +// fmt.Println(lm.PacketCount()) +// +// for ii := 0; ii < lm.PacketCount(); ii++ { +// +// pack := lm.Packet(ii) +// +// //fmt.Println(pack) +// +// client.Write(pack.Buffer) +// +// bytes := make([]byte, 1024) +// +// read, _ := client.Read(bytes) +// +// fmt.Println(cap(bytes)) +// +// //fmt.Println(bytes) +// +// b := lm.Match(ii+1, packet.NewPacket(bytes, read), scanInfo) +// +// if b { +// t.Log("send Good!") +// } +// +// } +// t.Log(scanInfo) +// +//} +// +//func TestIMapTls(t *testing.T) { +// +// conn, _ := tls.Dial( +// "tcp", +// "192.168.1.215:993", +// &tls.Config{ +// InsecureSkipVerify: true, +// ServerName: "192.168.1.215", +// }, +// ) +// +// defer conn.Close() +// +// ImapRun(conn, t) +// +//} +// +//func TestIMapNormal(t *testing.T) { +// +// client, _ := net.Dial("tcp", "192.168.1.215:143") +// +// defer client.Close() +// +// ImapRun(client, t) +// +//} +// +//func TestImap(t *testing.T) { +// +// lm := NewIMAPMatcher() +// +// //port := types.NewPort("143", types.NewHost("192.168.1.215"), types.TYPE_TCP) +// +// //scanInfo := scaninfo.NewServiceScanInfo(port) +// +// var ipport string +// //ipport = port.Host.Ip + ":" + port.Port_ +// +// fmt.Println(ipport) +// client, _ := net.Dial("tcp", ipport) +// +// defer client.Close() +// +// bytett := make([]byte, 1024) +// +// rr, _ := client.Read(bytett) +// +// //bb := lm.Match(0, packet.NewPacket(bytett, rr), scanInfo) +// bb := lm.Match(0, packet.NewPacket(bytett, rr), nil) +// +// if bb { +// t.Log("good!") +// } +// +// fmt.Println(lm.PacketCount()) +// +// for ii := 0; ii < lm.PacketCount(); ii++ { +// +// pack := lm.Packet(ii) +// +// //fmt.Println(pack) +// +// client.Write(pack.Buffer) +// +// bytes := make([]byte, 1024) +// +// read, _ := client.Read(bytes) +// +// fmt.Println(cap(bytes)) +// +// //fmt.Println(bytes) +// +// b := lm.Match(ii+1, packet.NewPacket(bytes, read), nil) +// +// if b { +// t.Log("send Good!") +// } +// +// } +// //t.Log(scanInfo) +//} diff --git a/matcher/ldap/ldap.go b/matcher/ldap/ldap.go new file mode 100644 index 0000000..c1c0ada --- /dev/null +++ b/matcher/ldap/ldap.go @@ -0,0 +1,198 @@ +package ldap + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +type LDAPMatcher struct { + sendPackets []*packet.Packet +} + +func (l *LDAPMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + buf := new(bytes.Buffer) + buf.Write(packet.Buffer) + + ldapRecv := LDAP_RECV{} + + binary.Read(buf, binary.LittleEndian, &ldapRecv) + + if ldapRecv.MessageId != LDAP_MESSAGE_ID { + return false + } + + if ldapRecv.ProtocolOp != LDAP_RES_BIND { + return false + } + + if ldapRecv.ResultCode != LDAP_SUCCESS { + return false + } + + return true +} + +func (l *LDAPMatcher) PacketCount() int { + return len(l.sendPackets) +} +func (l *LDAPMatcher) Packet(index int) *packet.Packet { + return l.sendPackets[index] +} +func (l *LDAPMatcher) ServiceName() string { + return "LDAP" +} + +func (l *LDAPMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} +func (l *LDAPMatcher) IsNoResponse(index int) bool { + + if index == 1 { + return true + } + + return false +} + +func (l *LDAPMatcher) IsPrePacket() bool { + return false +} + +func NewLDAPMatcher() *LDAPMatcher { + + ls := LDAP_SEND{ + DefaultCode: 0x30, + PacketLength: 0x0c, // size -2 + NextType1: 0x02, + NextTypeLength1: 0x01, + MessageId: LDAP_MESSAGE_ID, + ProtocolOp: LDAP_REQ_BIND, + ProtocolOpLength: 0x07, + NextType2: 0x02, + NextTypeLength2: 0x01, + Version: LDAP_VERSION3, + NextType3: 0x04, + NextTypeLength3: 0x00, + Auth: LDAP_AUTH_SIMPLE, + AuthLength: 0x00, + } + + mCache := new(bytes.Buffer) + binary.Write(mCache, binary.LittleEndian, ls) + + sendByte1 := mCache.Bytes() + + lm := LDAPMatcher{ + //sendPackets: make([][]byte, 2), + } + + pp := packet.NewPacket(sendByte1, len(sendByte1)) + + lm.sendPackets = append(lm.sendPackets, pp) + + lq := LDAP_QUIT{ + DefaultCode: 0x30, + UnknwonCode1: 0x84, + PacketLength: 0x05, + NextType1: 0x02, + NextTypeLength1: 0x01, + MessageId: LDAP_MESSAGE_ID_QUIT, + ProtocolOp: LDAP_REQ_UNBIND, + protocolOpLength: 0x00, + } + + lqBuffer := new(bytes.Buffer) + binary.Write(lqBuffer, binary.BigEndian, lq) + + sendByte2 := lqBuffer.Bytes() + + pp2 := packet.NewPacket(sendByte2, len(sendByte2)) + + lm.sendPackets = append(lm.sendPackets, pp2) + + return &lm + +} + +type LDAP_SEND struct { + DefaultCode uint8 + PacketLength uint8 + + NextType1 uint8 + NextTypeLength1 uint8 + + MessageId uint8 + + ProtocolOp uint8 + ProtocolOpLength uint8 + NextType2 uint8 + NextTypeLength2 uint8 + + Version uint8 + + NextType3 uint8 + NextTypeLength3 uint8 + Auth uint8 + AuthLength uint8 +} + +type LDAP_RECV struct { + DefaultCode uint8 + UnknwonCode1 uint8 + EndCode11 uint8 + EndCode12 uint8 + + MessageId uint8 + + ProtocolOp uint8 + UnknwonCode2 uint8 + EndCode21 uint8 + EndCode22 uint8 + + ResultCode uint8 + + UnknwonCode3 uint8 + UnknwonCode4 uint8 + Auth uint8 + UnknwonCode5 uint8 +} + +type LDAP_QUIT struct { + DefaultCode uint8 + UnknwonCode1 uint8 + + PacketLength uint32 + + NextType1 uint8 + NextTypeLength1 uint8 + + MessageId uint8 + + ProtocolOp uint8 + + protocolOpLength uint8 +} + +const ( + LDAP_MESSAGE_ID = 0x99 + LDAP_MESSAGE_ID_QUIT = 0x89 + + LDAP_VERSION3 = 3 + + LDAP_SUCCESS = 0x00 + + LDAP_REQ_BIND = 0x60 + + LDAP_REQ_UNBIND = 0x42 + + LDAP_RES_BIND = 0x61 + + LDAP_AUTH_SIMPLE = 0x80 +) diff --git a/matcher/ldap/ldap_test.go b/matcher/ldap/ldap_test.go new file mode 100644 index 0000000..2682bb6 --- /dev/null +++ b/matcher/ldap/ldap_test.go @@ -0,0 +1,110 @@ +package ldap + +// +//import ( +// "crypto/tls" +// "fmt" +// "loafle.com/overflow/collector/discovery/scan/matcher/packet" +// "loafle.com/overflow/collector/discovery/scan/matcher/scaninfo" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +////func SetUp() { +//// fmt.Println("SetUp") +////} +//// +////func TearDown() { +//// fmt.Println("TearDown") +////} +// +////func TestMain(m *testing.M) { +//// SetUp() +//// m.Run() +//// TearDown() +////} +// +//func TestAAAA(t *testing.T) { +// ///animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}} +// +// var ttt [][]int = make([][]int, 10) +// +// var aaa []int +// aaa = append(aaa, 111) +// +// ttt = append(ttt, aaa) +// +// fmt.Println(cap(ttt)) +// +//} +// +//func ldapRun(client net.Conn, t *testing.T) { +// lm := NewLDAPMatcher() +// +// port := types.NewPort("389", types.NewHost("192.168.1.215"), types.TYPE_TCP) +// scanInfo := scaninfo.NewServiceScanInfo(port) +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// fmt.Println(ipport) +// //client, _ := net.Dial("tcp", ipport) +// //defer client.Close() +// +// fmt.Println(lm.PacketCount()) +// +// for ii := 0; ii < lm.PacketCount(); ii++ { +// +// pack := lm.Packet(ii) +// +// bytes := make([]byte, 1024) +// +// client.Write(pack.Buffer) +// +// read, _ := client.Read(bytes) +// +// if read <= 0 { +// bb := lm.IsNoResponse(ii) +// if bb { +// +// t.Log("IsNoResponse good") +// break +// } +// +// } +// +// fmt.Println(bytes) +// +// b := lm.Match(ii, packet.NewPacket(bytes, read), scanInfo) +// +// if b { +// t.Log("Good") +// } +// +// } +// +// t.Log(scanInfo) +//} +// +//func TestLdapTls(t *testing.T) { +// conn, _ := tls.Dial( +// "tcp", +// "192.168.1.215:636", +// &tls.Config{ +// InsecureSkipVerify: true, +// ServerName: "192.168.1.215", +// }, +// ) +// +// defer conn.Close() +// +// ldapRun(conn, t) +//} +// +//func TestLdapNormal(t *testing.T) { +// client, _ := net.Dial("tcp", "192.168.1.215:389") +// +// defer client.Close() +// +// ldapRun(client, t) +//} diff --git a/matcher/matcher.go b/matcher/matcher.go new file mode 100644 index 0000000..a72ccb8 --- /dev/null +++ b/matcher/matcher.go @@ -0,0 +1,115 @@ +package matcher + +import ( + //"loafle.com/overflow/collector/core/scan/service/matcher/activedirectory" + //"loafle.com/overflow/collector/core/scan/service/matcher/cassandra" + //"loafle.com/overflow/collector/core/scan/service/matcher/dns" + //"loafle.com/overflow/collector/core/scan/service/matcher/ftp" + //"loafle.com/overflow/collector/core/scan/service/matcher/http" + //"loafle.com/overflow/collector/core/scan/service/matcher/imap" + //"loafle.com/overflow/collector/core/scan/service/matcher/ldap" + //"loafle.com/overflow/collector/core/scan/service/matcher/mongodb" + //"loafle.com/overflow/collector/core/scan/service/matcher/mssql" + //"loafle.com/overflow/collector/core/scan/service/matcher/mysql" + //"loafle.com/overflow/collector/core/scan/service/matcher/netbios" + "loafle.com/overflow/commons_go/matcher/oracle" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" + //"loafle.com/overflow/collector/core/scan/service/matcher/pop" + //"loafle.com/overflow/collector/core/scan/service/matcher/redis" + //"loafle.com/overflow/collector/core/scan/service/matcher/rmi" + //"loafle.com/overflow/collector/core/scan/service/matcher/smb" + //"loafle.com/overflow/collector/core/scan/service/matcher/smtp" + //"loafle.com/overflow/collector/core/scan/service/matcher/snmp" + //"loafle.com/overflow/collector/core/scan/service/matcher/ssh" + //"loafle.com/overflow/collector/core/scan/service/matcher/telnet" + //"loafle.com/overflow/collector/core/scan/service/matcher/wmi" +) + +var ( + TcpMatchers []Matcher + UdpMatchers []UDPMatcher +) + +func init() { + //TCP + //TcpMatchers = append(TcpMatchers, smtp.NewSmtpMatcher()) + //TcpMatchers = append(TcpMatchers, ldap.NewLDAPMatcher()) + //TcpMatchers = append(TcpMatchers, activedirectory.NewActiveDirectoryMatcher()) + //TcpMatchers = append(TcpMatchers, mongodb.NewMongoDBMatcher()) + //TcpMatchers = append(TcpMatchers, mysql.NewMySqlMatcher()) + //TcpMatchers = append(TcpMatchers, mssql.NewMSSqlMatcher()) + //TcpMatchers = append(TcpMatchers, redis.NewRedisMatcher()) + //TcpMatchers = append(TcpMatchers, redis.NewRedisProtectedMatcher()) + //TcpMatchers = append(TcpMatchers, netbios.NewNetBiosMatcher()) + //TcpMatchers = append(TcpMatchers, smb.NewSMBMatcher()) + //TcpMatchers = append(TcpMatchers, cassandra.NewCassandraMatcher()) + //TcpMatchers = append(TcpMatchers, imap.NewIMAPMatcher()) + TcpMatchers = append(TcpMatchers, oracle.NewOracleMatcher()) + //TcpMatchers = append(TcpMatchers, pop.NewPOPMatcher()) + //TcpMatchers = append(TcpMatchers, wmi.NewWMIMatcher()) + //TcpMatchers = append(TcpMatchers, ftp.NewFTPMatcher()) + //TcpMatchers = append(TcpMatchers, http.NewHTTPMatcher()) + //TcpMatchers = append(TcpMatchers, rmi.NewRMIMatcher()) + //TcpMatchers = append(TcpMatchers, ssh.NewSSHMatcher()) + //TcpMatchers = append(TcpMatchers, telnet.NewTelnetMatcher()) + //UdpMatchers = append(UdpMatchers, dns.NewDnsMatcher()) + //UdpMatchers = append(UdpMatchers, snmp.NewSNMPv2Matcher()) + //UdpMatchers = append(UdpMatchers, snmp.NewSNMPv3Matcher()) +} + +type Matcher interface { + Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool + + PacketCount() int + Packet(index int) *packet.Packet + ServiceName() string + + IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool + IsNoResponse(index int) bool + IsPrePacket() bool +} + +type UDPMatcher interface { + Matcher + IsSend(port int) bool +} + +func GetTcpMatchers(ispre bool) []Matcher { + + retMatchers := make([]Matcher, 0) + l := len(TcpMatchers) + for i := 0; i < l; i++ { + c := TcpMatchers[i].IsPrePacket() + if c == ispre { + retMatchers = append(retMatchers, TcpMatchers[i]) + } + } + + return retMatchers +} + +func GetUdpMatchers() []UDPMatcher { + + retMatchers := make([]UDPMatcher, 0) + l := len(UdpMatchers) + for i := 0; i < l; i++ { + retMatchers = append(retMatchers, UdpMatchers[i]) + } + + return retMatchers +} + +func GetMatcherByName(serName string) Matcher { + for _, m := range TcpMatchers { + if m.ServiceName() == serName { + return m + } + } + for _, m := range UdpMatchers { + if m.ServiceName() == serName { + return m + } + } + return nil +} diff --git a/matcher/matcher_test.go b/matcher/matcher_test.go new file mode 100644 index 0000000..83b63e9 --- /dev/null +++ b/matcher/matcher_test.go @@ -0,0 +1,87 @@ +package matcher + +import ( + "fmt" + "testing" +) + +type TestMatcher struct { +} + +func (t *TestMatcher) ServiceName() string { + return "TestMatcher" +} + +func (t *TestMatcher) Match(index int, packet []byte, info ServiceScanInfo) bool { + return true +} + +func (t *TestMatcher) PacketCount() int { + return 1 +} +func (t *TestMatcher) Packet(index int) []byte { + return nil +} + +func (t *TestMatcher) IsError(index int, packet []byte, info ServiceScanInfo) bool { + return true +} +func (t *TestMatcher) IsNoResponse(index int) bool { + return true +} +func (t *TestMatcher) IsPrePacket() bool { + return true +} + +type Animal interface { + Speak() string +} + +type Dog struct { +} + +func (d Dog) Speak() string { + return "Woof!" +} + +type Cat struct { +} + +func (c Cat) Speak() string { + return "Meow!" +} + +type Llama struct { +} + +func (l Llama) Speak() string { + return "?????" +} + +type JavaProgrammer struct { +} + +func (j JavaProgrammer) Speak() string { + return "Design patterns!" +} + +func TestMatcherTTT(t *testing.T) { + + //animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}} + + var animals []Animal + + animals = append(animals, &Dog{}) + animals = append(animals, &Cat{}) + animals = append(animals, &Llama{}) + animals = append(animals, &JavaProgrammer{}) + + for _, a := range animals { + fmt.Println(a.Speak()) + } + +} + +func TestMatchersInit(t *testing.T) { + +} diff --git a/matcher/mongodb/mongodb.go b/matcher/mongodb/mongodb.go new file mode 100644 index 0000000..ee80a38 --- /dev/null +++ b/matcher/mongodb/mongodb.go @@ -0,0 +1,122 @@ +package mongodb + +import ( + "bytes" + "encoding/binary" + "math/rand" + + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + MONGO_OP_REQUEST uint32 = 2004 + MONGO_OP_REPLY uint32 = 1 + MONGO_FCNAME string = "admin.$cmd" + MONGO_ELEMENT string = "ismaster" +) + +var MONGO_REQUEST_ID uint32 + +type mongo struct { + MessageLength uint32 + RequestId uint32 + ResponseTo uint32 + OpCode uint32 + Flags uint32 + FullCollectionName [11]byte + NumberToSkip uint32 + NumberToReturn int32 + DocumentLength uint32 + Type_ uint8 + Element [9]byte + Value uint8 + _ uint8 +} + +type MongoDBMatcher struct { + packets []*packet.Packet +} + +func NewMongoDBMatcher() *MongoDBMatcher { + + mongoMatcher := &MongoDBMatcher{} + + tempBuf := new(bytes.Buffer) + binary.Write(tempBuf, binary.BigEndian, mongo{}) + + var fcn [11]byte + copy(fcn[:], MONGO_FCNAME) + + var elem [9]byte + copy(elem[:], MONGO_ELEMENT) + + MONGO_REQUEST_ID = rand.Uint32() + m := mongo{ + MessageLength: uint32(len(tempBuf.Bytes())), + RequestId: MONGO_REQUEST_ID, + ResponseTo: 0, + OpCode: MONGO_OP_REQUEST, + Flags: 0, + FullCollectionName: fcn, + NumberToSkip: 0, + NumberToReturn: -1, + DocumentLength: 16, + Type_: 0x08, + Element: elem, + Value: 1, + } + writer := new(bytes.Buffer) + binary.Write(writer, binary.LittleEndian, m) + + mongoMatcher.packets = append(mongoMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len())) + + return mongoMatcher +} + +func (t *MongoDBMatcher) ServiceName() string { + return "MongoDB" +} + +func (t *MongoDBMatcher) PacketCount() int { + return len(t.packets) +} +func (t *MongoDBMatcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *MongoDBMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *MongoDBMatcher) IsNoResponse(index int) bool { + return false +} + +func (t *MongoDBMatcher) IsPrePacket() bool { + return false +} + +func (t *MongoDBMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + reader := new(bytes.Buffer) + reader.Write(packet.Buffer) + + m := mongo{} + if err := binary.Read(reader, binary.LittleEndian, &m); err != nil { + return false + } + + if uint32(packet.Len) != m.MessageLength || + m.ResponseTo != MONGO_REQUEST_ID || + m.OpCode != MONGO_OP_REPLY { + return false + } + + return true + +} diff --git a/matcher/mongodb/mongodb_test.go b/matcher/mongodb/mongodb_test.go new file mode 100644 index 0000000..4e09406 --- /dev/null +++ b/matcher/mongodb/mongodb_test.go @@ -0,0 +1,55 @@ +package mongodb + +// +//import ( +// "crypto/tls" +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//func TestMongoNor(t *testing.T) { +// +// conn, _ := net.Dial("tcp", "192.168.1.105:27017") +// +// defer conn.Close() +// +// MongoRun(conn, t) +// +//} +//func TestMongoTLS(t *testing.T) { +// conn, _ := tls.Dial( +// "tcp", +// "192.168.1.105:27017", +// &tls.Config{ +// InsecureSkipVerify: true, +// ServerName: "192.168.1.105", +// }, +// ) +// +// defer conn.Close() +// +// MongoRun(conn, t) +//} +// +//func MongoRun(conn net.Conn, t *testing.T) { +// +// m := NewMongoDBMatcher() +// +// 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("MongoDB found") +// return +// } +// +// t.Error("MongoDB not found") +// } +// +//} diff --git a/matcher/mssql/mssql.go b/matcher/mssql/mssql.go new file mode 100644 index 0000000..772a35b --- /dev/null +++ b/matcher/mssql/mssql.go @@ -0,0 +1,173 @@ +package mssql + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +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 MSSqlMatcher struct { + packets []*packet.Packet + isSSL bool +} + +func NewMSSqlMatcher() *MSSqlMatcher { + + mssqlMatcher := &MSSqlMatcher{} + + 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) + + mssqlMatcher.packets = append(mssqlMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len())) + + return mssqlMatcher +} + +func (t *MSSqlMatcher) ServiceName() string { + if t.isSSL { + return "SQL Server (SSL)" + } + return "SQL Server" +} + +func (t *MSSqlMatcher) PacketCount() int { + return len(t.packets) +} +func (t *MSSqlMatcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *MSSqlMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *MSSqlMatcher) IsNoResponse(index int) bool { + return false +} + +func (t *MSSqlMatcher) IsPrePacket() bool { + return false +} + +func (t *MSSqlMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + reader := new(bytes.Buffer) + reader.Write(packet.Buffer) + + m := mssqlResponse{} + + if err := binary.Read(reader, binary.BigEndian, &m); err != nil { + return false + } + + if m.Type_ != HEADER_TYPE_RESPONSE { + return false + } + + if m.Length != uint16(packet.Len) { + return false + } + + switch m.PreLoginResp.Msg[m.Length-9 : m.Length-8][0] { + case 0: + return true + case 1: + t.isSSL = true + return true + case 2: + return true + case 3: + t.isSSL = true + return true + default: + return false + } + + return false + +} diff --git a/matcher/mssql/mssql_test.go b/matcher/mssql/mssql_test.go new file mode 100644 index 0000000..199d11c --- /dev/null +++ b/matcher/mssql/mssql_test.go @@ -0,0 +1,64 @@ +package mssql + +// +//import ( +// "loafle.com/overflow/collector/discovery/scan/matcher/packet" +// "net" +// "testing" +//) +// +///* +//192.168.1.106:1433 - normal +//192.168.1.103:1433 - ssl +//*/ +//func TestSqlNor(t *testing.T) { +// +// conn, _ := net.Dial("tcp", "192.168.1.103:1433") +// +// defer conn.Close() +// +// sqlServerRun(conn, t) +// +//} +// +////func TestSqlTLS(t *testing.T) { +//// conn, err := tls.Dial( +//// "tcp", +//// "192.168.1.103:7680", +//// &tls.Config{ +//// InsecureSkipVerify: true, +//// ServerName: "192.168.1.103", +//// }, +//// ) +//// +//// if err != nil { +//// t.Log(err) +//// return +//// } +//// +//// defer conn.Close() +//// +//// sqlServerRun(conn, t) +////} +// +//func sqlServerRun(conn net.Conn, t *testing.T) { +// +// m := NewMSSqlMatcher() +// +// 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("MSSQL not found") +// } +// +//} diff --git a/matcher/mysql/mysql.go b/matcher/mysql/mysql.go new file mode 100644 index 0000000..15264dd --- /dev/null +++ b/matcher/mysql/mysql.go @@ -0,0 +1,151 @@ +package mysql + +import ( + "bytes" + "encoding/binary" + "fmt" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/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) IsNoResponse(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 + } + } + } +} diff --git a/matcher/mysql/mysql_test.go b/matcher/mysql/mysql_test.go new file mode 100644 index 0000000..29c294c --- /dev/null +++ b/matcher/mysql/mysql_test.go @@ -0,0 +1,71 @@ +package mysql + +// +//import ( +// "crypto/tls" +// "loafle.com/overflow/collector/core/scan/service/matcher/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.215:3306") +// +// 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") +// } +// +//} diff --git a/matcher/netbios/netbios.go b/matcher/netbios/netbios.go new file mode 100644 index 0000000..06abe81 --- /dev/null +++ b/matcher/netbios/netbios.go @@ -0,0 +1,109 @@ +package netbios + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + NBSS_SESSION_REQUEST uint8 = 0x81 + NBSS_POSITIVE_SESSION_RESPONSE uint8 = 0x82 + NBSS_NEGATIVE_SESSION_RESPONSE uint8 = 0x83 + ADDR string = "192.168.1.202:139" +) + +type netBios struct { + MsgType uint8 + Flags uint8 //0-6 : Reserved, must be zero. 7 : Length extension. + Length uint16 + CalledNameLen uint8 + CalledName [16]uint16 + _ uint8 + CallingNameLen uint8 + CallingName [16]uint16 + _ uint8 +} + +type NetBiosMatcher struct { + packets []*packet.Packet +} + +func NewNetBiosMatcher() *NetBiosMatcher { + + nbssMatcher := &NetBiosMatcher{} + + tempBuf := new(bytes.Buffer) + binary.Write(tempBuf, binary.BigEndian, netBios{}) + + query := netBios{ + MsgType: NBSS_SESSION_REQUEST, + Flags: 0x00, + Length: 0x4400, + CalledNameLen: 0x20, + CallingNameLen: 0x20, + } + + query.CalledName[0] = 0x4D45 // L + query.CalledName[1] = 0x4745 // F + + query.CallingName[0] = 0x4D45 + query.CallingName[1] = 0x4745 + + for i := 2; i < 16; i++ { + query.CalledName[i] = 0x4143 //Space + query.CallingName[i] = 0x4143 + } + writer := new(bytes.Buffer) + binary.Write(writer, binary.LittleEndian, query) + + nbssMatcher.packets = append(nbssMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len())) + + return nbssMatcher +} + +func (t *NetBiosMatcher) ServiceName() string { + return "NBSS" +} + +func (t *NetBiosMatcher) PacketCount() int { + return len(t.packets) +} +func (t *NetBiosMatcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *NetBiosMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *NetBiosMatcher) IsNoResponse(index int) bool { + return false +} + +func (t *NetBiosMatcher) IsPrePacket() bool { + return false +} + +func (t *NetBiosMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + reader := new(bytes.Buffer) + reader.Write(packet.Buffer) + + n := netBios{} + if err := binary.Read(reader, binary.LittleEndian, &n); err != nil { + return false + } + + if NBSS_NEGATIVE_SESSION_RESPONSE != n.MsgType { + return false + } + + return true + +} diff --git a/matcher/netbios/netbios_test.go b/matcher/netbios/netbios_test.go new file mode 100644 index 0000000..701169d --- /dev/null +++ b/matcher/netbios/netbios_test.go @@ -0,0 +1,34 @@ +package netbios + +// +//import ( +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//func TestNBSS(t *testing.T) { +// +// m := NewNetBiosMatcher() +// +// conn, _ := net.Dial("tcp", "192.168.1.106:139") +// +// 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("NBSS found") +// return +// } +// +// t.Error("NBSS not found") +// } +// +//} diff --git a/matcher/oracle/oracle.go b/matcher/oracle/oracle.go new file mode 100644 index 0000000..0638c16 --- /dev/null +++ b/matcher/oracle/oracle.go @@ -0,0 +1,187 @@ +package oracle + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +type OracleMatcher struct { + sendPackets []*packet.Packet +} + +func (o *OracleMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + header := header_packet{} + refuse := body_refuse{} + + buf := new(bytes.Buffer) + buf.Write(packet.Buffer) + + binary.Read(buf, binary.BigEndian, &header) + binary.Read(buf, binary.BigEndian, &refuse) + + //fmt.Println(header) + //fmt.Println(refuse) + + if header.Check_sum != 0 { + return false + } + if header.Types != 4 { + return false + } + if header.Reserved_byte != 0 { + return false + } + if header.Header_sum != 0 { + return false + } + if refuse.Reason_user != 34 { + return false + } + if refuse.Reason_system != 0 { + return false + } + + var dataLen int = int(refuse.Data_len) + if dataLen != packet.Len-12 { + return false + } + + return true +} + +func (o *OracleMatcher) PacketCount() int { + return len(o.sendPackets) +} +func (o *OracleMatcher) Packet(index int) *packet.Packet { + return o.sendPackets[index] +} +func (o *OracleMatcher) ServiceName() string { + return "OracleMatcher" +} + +func (o *OracleMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} +func (o *OracleMatcher) IsNoResponse(index int) bool { + + return false +} + +func (o *OracleMatcher) IsPrePacket() bool { + return true +} + +func NewOracleMatcher() *OracleMatcher { + + pm := OracleMatcher{} + + hp := header_packet{ + Length: 247, + Check_sum: 0, + Types: 1, + Reserved_byte: 0, + Header_sum: 0, + } + + bc := body_connect{ + Version: 315, + Version_compatible: 300, + //Service_options: + Session_unit_size: 8192, + Maxumum_trans_data_unit_size: 65535, + //Nt_protocol_characteristics: + Line_turnaround_value: 0, + Value_of_1_in_hardware: 1, + Length_of_connect_data: 177, + Offset_to_connect_data: 70, + Maximum_receivable_connect_data: 0, + //Connect_flag0: + //Connect_flag1: + Trace_cross_facility_item_1: 0, + Trace_cross_facility_item_2: 0, + Trace_unique_connection_id: 0, + //Unknown_data: + //Connect_data: + + } + + bc.Service_options[0] = 0x0c + bc.Service_options[1] = 0x41 + + bc.Nt_protocol_characteristics[0] = 0x4f + bc.Nt_protocol_characteristics[1] = 0x98 + + bc.Connect_flag0 = 0x81 + bc.Connect_flag1 = 0x81 + + bc.Unknown_data[10] = 0x20 + bc.Unknown_data[13] = 0x20 + + conDataStr := "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.30)(PORT=1521))(CONNECT_DATA=(CID=(PROGRAM=JDBC Thin Client)(HOST=__jdbc__)(USER=loafle.match))(SERVICE_NAME=oracle.loafle.com.match)))" + connect_data := make([]byte, len(conDataStr)) + copy(connect_data, conDataStr) + + hpBuf := new(bytes.Buffer) + binary.Write(hpBuf, binary.BigEndian, hp) + + hpBt := hpBuf.Bytes() + + bcBuf := new(bytes.Buffer) + binary.Write(bcBuf, binary.BigEndian, bc) + bcBt := bcBuf.Bytes() + + byteSize := len(hpBt) + len(bcBt) + len(conDataStr) + sendByte := make([]byte, byteSize) + + copy(sendByte[0:], hpBt) + copy(sendByte[len(hpBt):], bcBt) + copy(sendByte[len(hpBt)+len(bcBt):], connect_data) + + pm.sendPackets = append(pm.sendPackets, packet.NewPacket(sendByte, byteSize)) + + return &pm + +} + +type header_packet struct { + Length uint16 + Check_sum uint16 + Types byte + Reserved_byte byte + Header_sum uint16 +} + +type body_connect struct { + Version uint16 + Version_compatible uint16 + Service_options [2]byte + Session_unit_size uint16 + Maxumum_trans_data_unit_size uint16 + Nt_protocol_characteristics [2]byte + Line_turnaround_value uint16 + Value_of_1_in_hardware uint16 + Length_of_connect_data uint16 + Offset_to_connect_data uint16 + Maximum_receivable_connect_data uint32 + Connect_flag0 byte + Connect_flag1 byte + Trace_cross_facility_item_1 uint32 + Trace_cross_facility_item_2 uint32 + Trace_unique_connection_id uint64 + Unknown_data [20]byte + //Connect_data []byte +} + +type body_refuse struct { + Reason_user byte + Reason_system byte + Data_len uint16 + //Data []byte +} diff --git a/matcher/oracle/oracle_test.go b/matcher/oracle/oracle_test.go new file mode 100644 index 0000000..dbef20e --- /dev/null +++ b/matcher/oracle/oracle_test.go @@ -0,0 +1,53 @@ +package oracle + +// +//import ( +// "fmt" +// "loafle.com/overflow/collector/discovery/scan/matcher/packet" +// "loafle.com/overflow/collector/discovery/scan/matcher/scaninfo" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +//func TestOracle(t *testing.T) { +// +// lm := NewOracleMatcher() +// +// port := types.NewPort("1521", types.NewHost("192.168.1.30"), types.TYPE_TCP) +// scanInfo := scaninfo.NewServiceScanInfo(port) +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// fmt.Println(ipport) +// client, _ := net.Dial("tcp", ipport) +// +// defer client.Close() +// +// fmt.Println(lm.PacketCount()) +// +// for ii := 0; ii < lm.PacketCount(); ii++ { +// +// pack := lm.Packet(ii) +// +// fmt.Println(pack) +// +// client.Write(pack.Buffer) +// +// bytes := make([]byte, 1024) +// +// read, _ := client.Read(bytes) +// +// fmt.Println(bytes) +// +// b := lm.Match(ii, packet.NewPacket(bytes, read), scanInfo) +// +// if b { +// t.Log("Good") +// } +// +// } +// +// t.Log(scanInfo) +// +//} diff --git a/matcher/packet/packet.go b/matcher/packet/packet.go new file mode 100644 index 0000000..9c7c1af --- /dev/null +++ b/matcher/packet/packet.go @@ -0,0 +1,13 @@ +package packet + +type Packet struct { + Buffer []byte + Len int +} + +func NewPacket(buf []byte, len int) *Packet { + return &Packet{ + Buffer: buf, + Len: len, + } +} diff --git a/matcher/pop/pop.go b/matcher/pop/pop.go new file mode 100644 index 0000000..d356199 --- /dev/null +++ b/matcher/pop/pop.go @@ -0,0 +1,73 @@ +package pop + +import ( + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + COMPARE_STR = "+OK" +) + +type POPMatcher struct { + sendPackets []*packet.Packet +} + +func (p *POPMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + switch index { + case 0: + fallthrough + case 1: + + recvStr := string(packet.Buffer) + + if len(recvStr) < 3 { + return false + } + + compareStr := recvStr[0:3] + + if compareStr == COMPARE_STR { + return true + } + + } + + return false +} + +func (p *POPMatcher) PacketCount() int { + return len(p.sendPackets) +} +func (p *POPMatcher) Packet(index int) *packet.Packet { + return p.sendPackets[index] +} +func (p *POPMatcher) ServiceName() string { + return "POPMatcher" +} + +func (p *POPMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} +func (p *POPMatcher) IsNoResponse(index int) bool { + + return false +} + +func (p *POPMatcher) IsPrePacket() bool { + return true +} + +func NewPOPMatcher() *POPMatcher { + + pm := POPMatcher{} + + reqStr := "QUIT\r\n" + byte := make([]byte, len(reqStr)) + copy(byte[:], reqStr) + pm.sendPackets = append(pm.sendPackets, packet.NewPacket(byte, len(reqStr))) + + return &pm + +} diff --git a/matcher/pop/pop_test.go b/matcher/pop/pop_test.go new file mode 100644 index 0000000..721fcbc --- /dev/null +++ b/matcher/pop/pop_test.go @@ -0,0 +1,86 @@ +package pop + +// +//import ( +// "crypto/tls" +// "fmt" +// "loafle.com/overflow/collector/discovery/scan/matcher/packet" +// "loafle.com/overflow/collector/discovery/scan/matcher/scaninfo" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +//func TestPopTLS(t *testing.T) { +// conn, _ := tls.Dial( +// "tcp", +// "192.168.1.215:995", +// &tls.Config{ +// InsecureSkipVerify: true, +// ServerName: "192.168.1.215", +// }, +// ) +// +// defer conn.Close() +// +// pop3Run(conn, t) +//} +// +//func TestPopNor(t *testing.T) { +// +// client, _ := net.Dial("tcp", "192.168.1.215:110") +// +// defer client.Close() +// +// pop3Run(client, t) +// +//} +// +//func pop3Run(client net.Conn, t *testing.T) { +// +// lm := NewPOPMatcher() +// +// port := types.NewPort("110", types.NewHost("192.168.1.215"), types.TYPE_TCP) +// scanInfo := scaninfo.NewServiceScanInfo(port) +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// fmt.Println(ipport) +// +// bytett := make([]byte, 1024) +// +// read, _ := client.Read(bytett) +// +// bb := lm.Match(0, packet.NewPacket(bytett, read), scanInfo) +// +// if bb { +// t.Log("good!") +// } +// +// fmt.Println(lm.PacketCount()) +// +// for ii := 0; ii < lm.PacketCount(); ii++ { +// +// pack := lm.Packet(ii) +// +// //fmt.Println(pack) +// +// client.Write(pack.Buffer) +// +// bytes := make([]byte, 1024) +// +// rr, _ := client.Read(bytes) +// +// //fmt.Println(bytes) +// +// b := lm.Match(ii+1, packet.NewPacket(bytes, rr), scanInfo) +// +// if b { +// t.Log("send Good!") +// } +// +// } +// +// t.Log(scanInfo) +// +//} diff --git a/matcher/redis/redis.go b/matcher/redis/redis.go new file mode 100644 index 0000000..d384855 --- /dev/null +++ b/matcher/redis/redis.go @@ -0,0 +1,76 @@ +package redis + +import ( + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" + "strings" +) + +const REDIS_PING string = "*1\r\n$4\r\nping\r\n" + +type RedisMatcher struct { + packets []*packet.Packet +} + +func NewRedisMatcher() *RedisMatcher { + + redisMatcher := &RedisMatcher{} + + redisMatcher.packets = append(redisMatcher.packets, packet.NewPacket([]byte(REDIS_PING), len(REDIS_PING))) + + return redisMatcher +} + +func (t *RedisMatcher) ServiceName() string { + return "Redis" +} + +func (t *RedisMatcher) PacketCount() int { + return len(t.packets) +} +func (t *RedisMatcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *RedisMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *RedisMatcher) IsNoResponse(index int) bool { + return false +} + +func (t *RedisMatcher) IsPrePacket() bool { + return false +} + +func (t *RedisMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + resp := strings.Split(string(packet.Buffer), "\r\n")[0] + if len(resp) <= 0 { + return false + } + + sign := string([]rune(resp)[0]) + if len(sign) <= 0 { + return false + } + + if sign == "+" { + if resp == "+PONG" || resp == "+OK" { + return true + } + } + if sign == "-" { + if resp == "-NOAUTH" || resp == "-ERR" { + return true + } + } + + return false + +} diff --git a/matcher/redis/redisProtected.go b/matcher/redis/redisProtected.go new file mode 100644 index 0000000..0f4b3b1 --- /dev/null +++ b/matcher/redis/redisProtected.go @@ -0,0 +1,78 @@ +package redis + +import ( + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + COMPARE_STR_1 = "-" + COMPARE_STR_2 = "DENIED" +) + +type RedisProtectedMatcher struct { +} + +func NewRedisProtectedMatcher() *RedisProtectedMatcher { + + redisMatcher := &RedisProtectedMatcher{} + + return redisMatcher +} + +func (r *RedisProtectedMatcher) ServiceName() string { + return "RedisProtectedMatcher" +} + +func (r *RedisProtectedMatcher) PacketCount() int { + return 0 +} +func (r *RedisProtectedMatcher) Packet(index int) *packet.Packet { + return nil +} + +func (r *RedisProtectedMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (r *RedisProtectedMatcher) IsNoResponse(index int) bool { + return false +} + +func (r *RedisProtectedMatcher) IsPrePacket() bool { + return true +} + +func (r *RedisProtectedMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + switch index { + case 0: + str := string(packet.Buffer[:packet.Len]) + + if str == "" { + return false + } + if len(str) <= 0 { + return false + } + + firstCompare := str[0:1] + seconcdCompare := str[1 : len(COMPARE_STR_2)+1] + + if firstCompare != COMPARE_STR_1 { + return false + } + if seconcdCompare != COMPARE_STR_2 { + return false + } + + return true + } + + return false + +} diff --git a/matcher/redis/redisProtected_test.go b/matcher/redis/redisProtected_test.go new file mode 100644 index 0000000..2dfc0b0 --- /dev/null +++ b/matcher/redis/redisProtected_test.go @@ -0,0 +1,33 @@ +package redis + +//import ( +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//func TestRedisProtected(t *testing.T) { +// +// m := NewRedisProtectedMatcher() +// +// conn, err := net.Dial("tcp", "192.168.1.215:8379") +// +// if err != nil { +// t.Log(err) +// return +// } +// +// defer conn.Close() +// +// bytes := make([]byte, 1024) +// n, _ := conn.Read(bytes) +// +// //fmt.Println(string(bytes[:n])) +// +// b := m.Match(0, packet.NewPacket(bytes, n), nil) +// +// if b { +// t.Log("good!") +// } +// +//} diff --git a/matcher/redis/redis_test.go b/matcher/redis/redis_test.go new file mode 100644 index 0000000..bc82304 --- /dev/null +++ b/matcher/redis/redis_test.go @@ -0,0 +1,38 @@ +package redis + +// +//import ( +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//const ( +// ADDR string = "192.168.1.215:6379" +//) +// +//func TestRedisMatcher(t *testing.T) { +// +// m := NewRedisMatcher() +// +// conn, _ := net.Dial("tcp", ADDR) +// 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("Redis found.") +// return +// } +// +// t.Error("Redis not found") +// } +// +//} diff --git a/matcher/rmi/rmi.go b/matcher/rmi/rmi.go new file mode 100644 index 0000000..712c7ee --- /dev/null +++ b/matcher/rmi/rmi.go @@ -0,0 +1,111 @@ +package rmi + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + MAGIC_NUMBER = 0x4a524d49 + STREAM_PROTOCOL = 0x4b + VERSION = 0x0002 + ACK_PROTOCOL = 0x4e +) + +type RMI_SEND_MESSAGE struct { + magic uint32 + version uint16 + protocol uint8 +} + +type RMI_RECV_MESSAGE struct { + streamMessage uint8 + packetLen uint16 + host []byte + port [2]byte +} +type RMIMatcher struct { + sendPackets []*packet.Packet +} + +func (r *RMIMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + result := false + + if packet == nil || packet.Buffer == nil || packet.Len == 0 { + return result + } + + //fmt.Println("packet :", packet) + rmiRecv := RMI_RECV_MESSAGE{} + + buf := bytes.NewReader(packet.Buffer) + binary.Read(buf, binary.BigEndian, &rmiRecv.streamMessage) + binary.Read(buf, binary.BigEndian, &rmiRecv.packetLen) + + lenInt := int(rmiRecv.packetLen) + + var tempHost = make([]byte, lenInt, lenInt) + copy(rmiRecv.host, tempHost) + + rmiRecv.host = tempHost + + binary.Read(buf, binary.BigEndian, &rmiRecv.host) + binary.Read(buf, binary.BigEndian, &rmiRecv.port) + + hostIp := string(rmiRecv.host[:lenInt]) + //fmt.Println(hostIp) + + //hostPort := binary.BigEndian.Uint16(rmiRecv.port[:2]) + + if rmiRecv.streamMessage == ACK_PROTOCOL && lenInt == len(hostIp) { + result = true + } + + return result +} + +func (r *RMIMatcher) PacketCount() int { + return len(r.sendPackets) +} + +func (r *RMIMatcher) Packet(index int) *packet.Packet { + return r.sendPackets[index] +} + +func (r *RMIMatcher) ServiceName() string { + return "RMI" +} + +func (r *RMIMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (r *RMIMatcher) IsNoResponse(index int) bool { + return false +} + +func (r *RMIMatcher) IsPrePacket() bool { + return false +} + +func NewRMIMatcher() *RMIMatcher { + + r := RMIMatcher{} + rsm := RMI_SEND_MESSAGE{ + magic: MAGIC_NUMBER, + version: VERSION, + protocol: STREAM_PROTOCOL, + } + + mCache := new(bytes.Buffer) + binary.Write(mCache, binary.BigEndian, rsm) + + sendByte1 := mCache.Bytes() + pp := packet.NewPacket(sendByte1, len(sendByte1)) + + r.sendPackets = append(r.sendPackets, pp) + + return &r +} diff --git a/matcher/rmi/rmi_test.go b/matcher/rmi/rmi_test.go new file mode 100644 index 0000000..7fe8f90 --- /dev/null +++ b/matcher/rmi/rmi_test.go @@ -0,0 +1,48 @@ +package rmi + +//import ( +// "fmt" +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +//func TestNew(t *testing.T) { +// r := NewRMIMatcher() +// fmt.Println("TestNew: ", r) +//} +//func TestRMIMatcher_Match(t *testing.T) { +// +// fmt.Println("Match") +// +// hm := NewRMIMatcher() +// +// port := types.NewPort("9840", types.NewHost("192.168.1.101"), types.TYPE_TCP) +// +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// //fmt.Println(ipport) +// +// client, _ := net.Dial("tcp", ipport) +// +// defer client.Close() +// +// pack := hm.Packet(0) +// +// fmt.Println(pack.Buffer) +// +// //writer.WriteString(pack) +// client.Write(pack.Buffer) +// +// bytes := make([]byte, 512) +// +// l, _ := client.Read(bytes) +// +// //fmt.Println(bytes) +// +// t1 := hm.Match(0, packet.NewPacket(bytes, l), nil) +// +// fmt.Println(t1) +//} diff --git a/matcher/smb/smb.go b/matcher/smb/smb.go new file mode 100644 index 0000000..c25dc99 --- /dev/null +++ b/matcher/smb/smb.go @@ -0,0 +1,161 @@ +package smb + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" + "strings" +) + +const ( + SMB_COM_NEGOTIATE uint8 = 0x72 + SMB_SUCCESS uint8 = 0x00 +) + +type netBIOS struct { + MsgType byte + MsgLength [3]uint8 +} + +type smb struct { + NetBios netBIOS + Component [4]uint8 + SmbCommand uint8 + NtStatus [4]uint8 + Flags uint8 + Flags2 [2]uint8 + ProcessId uint16 + Signature uint64 + Reserved uint16 + Tid uint16 + Pid uint16 + Uid uint16 + Mid uint16 + Wct uint8 + Bcc uint16 + Bf1 uint8 + Name1 [23]uint8 + Bf2 uint8 + Name2 [10]uint8 + Bf3 uint8 + Name3 [28]uint8 + Bf4 uint8 + Name4 [10]uint8 + Bf5 uint8 + Name5 [10]uint8 + Bf6 uint8 + Name6 [11]uint8 +} + +type SMBMatcher struct { + packets []*packet.Packet +} + +func NewSMBMatcher() *SMBMatcher { + + nbssMatcher := &SMBMatcher{} + + query := smb{} + query.NetBios.MsgType = 0x00 + query.NetBios.MsgLength[2] = 0x85 + + query.Component[0] = 0xff + query.Component[1] = 'S' + query.Component[2] = 'M' + query.Component[3] = 'B' + + query.SmbCommand = SMB_COM_NEGOTIATE + query.NtStatus[3] = SMB_SUCCESS + query.Flags = 0x18 + query.Flags2[0] = 0x53 + query.Flags2[1] = 0xC8 + + query.ProcessId = 0x00 + query.Signature = 0x00 + query.Reserved = 0 + query.Tid = 0 + query.Pid = 0xfeff + query.Uid = 0 + query.Mid = 0 + query.Wct = 0 + query.Bcc = 0x0062 + + query.Bf1 = 0x02 + copy(query.Name1[:], "PC NETWORK PROGRAM 1.0") + + query.Bf2 = 0x02 + copy(query.Name2[:], "LANMAN1.0") + + query.Bf3 = 0x02 + copy(query.Name3[:], "Windows for Workgroups 3.1a") + + query.Bf4 = 0x02 + copy(query.Name4[:], "LM1.2X002") + + query.Bf5 = 0x02 + copy(query.Name5[:], "LANMAN2.1") + + query.Bf6 = 0x02 + copy(query.Name6[:], "NT LM 0.12") + + writer := new(bytes.Buffer) + binary.Write(writer, binary.LittleEndian, query) + + nbssMatcher.packets = append(nbssMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len())) + + return nbssMatcher +} + +func (t *SMBMatcher) ServiceName() string { + return "SMB" +} + +func (t *SMBMatcher) PacketCount() int { + return len(t.packets) +} +func (t *SMBMatcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *SMBMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *SMBMatcher) IsNoResponse(index int) bool { + return false +} + +func (t *SMBMatcher) IsPrePacket() bool { + return false +} + +func (t *SMBMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + reader := new(bytes.Buffer) + reader.Write(packet.Buffer) + + s := smb{} + if err := binary.Read(reader, binary.BigEndian, &s); err != nil { + return false + } + + var des [4]byte + copy(des[1:], s.NetBios.MsgLength[:]) + packetLen := binary.BigEndian.Uint32(des[:]) + + if packetLen != uint32(packet.Len-4) { + return false + } + + if !strings.Contains(string(s.Component[:]), "SMB") { + return false + } + + return true + +} diff --git a/matcher/smb/smb_test.go b/matcher/smb/smb_test.go new file mode 100644 index 0000000..b534bc1 --- /dev/null +++ b/matcher/smb/smb_test.go @@ -0,0 +1,37 @@ +package smb + +//import ( +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//const ( +// ADDR string = "192.168.1.104:139" +//) +// +//func TestSMBMatcher(t *testing.T) { +// +// m := NewSMBMatcher() +// +// conn, _ := net.Dial("tcp", ADDR) +// 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("SMB found.") +// return +// } +// +// t.Error("SMB not found") +// } +// +//} diff --git a/matcher/smtp/smtp.go b/matcher/smtp/smtp.go new file mode 100644 index 0000000..8c15d35 --- /dev/null +++ b/matcher/smtp/smtp.go @@ -0,0 +1,71 @@ +package smtp + +import ( + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" + "strings" +) + +type SmtpMatcher struct { + packets []*packet.Packet +} + +func NewSmtpMatcher() *SmtpMatcher { + + m := &SmtpMatcher{} + b := []byte("helo test\r\n") + m.packets = append(m.packets, packet.NewPacket(b, len(b))) + b = []byte("quit\r\n") + m.packets = append(m.packets, packet.NewPacket(b, len(b))) + return m +} + +func (t *SmtpMatcher) ServiceName() string { + return "SMTP" +} + +func (t *SmtpMatcher) PacketCount() int { + return len(t.packets) +} +func (t *SmtpMatcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *SmtpMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *SmtpMatcher) IsNoResponse(index int) bool { + return false +} + +func (t *SmtpMatcher) IsPrePacket() bool { + return true +} + +func (t *SmtpMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + if packet == nil { + return false + } + buf := string(packet.Buffer) + if len(buf) == 0 || len(buf) < 5 { + return false + } + + splits := strings.Split(buf, "\r\n") + splits = strings.Split(buf, " ") + if index == 0 { + if splits[0] == "220" { + return true + } + } else if index == 1 { + if splits[0] == "250" { + return true + } + } else if index == 2 { + if splits[0] == "221" { + return true + } + } + return false +} diff --git a/matcher/smtp/smtp_test.go b/matcher/smtp/smtp_test.go new file mode 100644 index 0000000..b2cfc08 --- /dev/null +++ b/matcher/smtp/smtp_test.go @@ -0,0 +1,68 @@ +package smtp + +// +//import ( +// "crypto/tls" +// "fmt" +// "github.com/stretchr/testify/assert" +// "net" +// "strings" +// "testing" +//) +// +//func TestSMTPTLS(t *testing.T) { +// +// conn, err := tls.Dial("tcp", +// "192.168.1.215:465", +// &tls.Config{ +// InsecureSkipVerify: true, +// ServerName: "192.168.1.215", +// }, +// ) +// +// if err != nil { +// t.Log(err) +// return +// } +// +// b := make([]byte, 1024) +// +// check(t, b, conn, "", "220") +// check(t, b, conn, "helo test\r\n", "250") +// check(t, b, conn, "quit\r\n", "221") +// +// conn.Close() +//} +// +//func TestSMTP(t *testing.T) { +// +// conn, _ := net.Dial("tcp", "192.168.1.215:25") +// +// b := make([]byte, 1024) +// +// check(t, b, conn, "", "220") +// check(t, b, conn, "helo test\r\n", "250") +// check(t, b, conn, "quit\r\n", "221") +// +// conn.Close() +// +//} +//func check(t *testing.T, b []byte, conn net.Conn, cmd string, compare string) { +// +// if cmd != "" { +// wlen, _ := conn.Write([]byte(cmd)) +// assert.Equal(t, wlen, len(cmd)) +// } +// +// rlen, _ := conn.Read(b) +// +// fmt.Println(rlen) +// fmt.Println(len(b)) +// +// data := string(b[:rlen]) +// fmt.Println(data) +// assert.Equal(t, true, rlen > 4) +// splits := strings.Split(data, " ") +// assert.Equal(t, compare, splits[0]) +// +//} diff --git a/matcher/snmp/snmpv2.go b/matcher/snmp/snmpv2.go new file mode 100644 index 0000000..850ecb1 --- /dev/null +++ b/matcher/snmp/snmpv2.go @@ -0,0 +1,200 @@ +package snmp + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + SNMP_START_SEQUENCE uint8 = 0X30 + SNMP_TYPE_INTEGER uint8 = 0X02 + SNMP_TYPE_STRING uint8 = 0X04 + SNMP_TYPE_NULL uint8 = 0X05 + SNMP_TYPE_OBJECT uint8 = 0X06 + SNMP_GET_REQUEST uint8 = 0XA0 + //SNMP_RESPONSE uint8 = 0XA2 + SNMP_NO_DESC uint16 = 0X0004 + SNMP_END_SEQUENCE uint8 = 0X30 + SNMP_PROTOCOL_VERSION_3 uint8 = 0X03 + SNMP_PROTOCOL_VERSION_2c uint8 = 0X01 + SNMP_MSG_ID_MAX_VALUE uint32 = 0xFFFFFF7F +) + +type snmpv2VarBinding struct { + VarBindindStart uint8 + VarBindLen uint8 + ObjectStart uint8 + ObjectLen uint8 + ValueType uint8 + ValueLen uint8 + ObjectValue uint64 + NullValue uint8 + EndIndicator uint8 +} + +type snmpv2Data struct { + DataType uint8 + DataLen uint8 + RequestIdType uint8 + RequestIdLen uint8 + RequestId uint8 + ErrorStatusType uint8 + ErrorStatusLen uint8 + ErrorStatus uint8 + ErrorIndexType uint8 + ErrorIndexLen uint8 + ErrorIndex uint8 + + VarBinding snmpv2VarBinding +} + +type snmpv2 struct { + StartSeq uint8 + SeqLen uint8 + SNMPVersionType uint8 + SNMPVersionLen uint8 + SNMPVersion uint8 + CommunityVersionType uint8 + CommunityVersionLen uint8 + Community [6]byte + + Data snmpv2Data +} + +type SNMPv2Matcher struct { + packets []*packet.Packet +} + +func NewSNMPv2Matcher() *SNMPv2Matcher { + + snmpMatcher := &SNMPv2Matcher{} + + snmpTempBuf := new(bytes.Buffer) + binary.Write(snmpTempBuf, binary.BigEndian, snmpv2{}) //For getting the struct size + + snmpDataTempBuf := new(bytes.Buffer) + binary.Write(snmpDataTempBuf, binary.BigEndian, snmpv2Data{}) //For getting the struct size + + snmpVarTempBuf := new(bytes.Buffer) + binary.Write(snmpVarTempBuf, binary.BigEndian, snmpv2VarBinding{}) //For getting the struct size + + q := snmpv2{} + q.StartSeq = SNMP_START_SEQUENCE + q.SeqLen = uint8(len(snmpTempBuf.Bytes())) - 2 + q.SNMPVersionType = SNMP_TYPE_INTEGER + q.SNMPVersionLen = 0x01 + q.SNMPVersion = SNMP_PROTOCOL_VERSION_2c + q.CommunityVersionType = SNMP_TYPE_STRING + q.CommunityVersionLen = 0x06 + var community [6]byte + copy(community[:], "public") + q.Community = community + q.Data.DataType = SNMP_GET_REQUEST + q.Data.DataLen = uint8(len(snmpDataTempBuf.Bytes())) - 2 + q.Data.RequestIdType = SNMP_TYPE_INTEGER + q.Data.RequestIdLen = 0x01 + q.Data.RequestId = 0x01 + q.Data.ErrorStatusType = SNMP_TYPE_INTEGER + q.Data.ErrorStatusLen = 0x01 + q.Data.ErrorStatus = 0x00 + q.Data.ErrorIndexType = SNMP_TYPE_INTEGER + q.Data.ErrorIndexLen = 0x01 + q.Data.ErrorIndex = 0x00 + q.Data.VarBinding.VarBindindStart = SNMP_START_SEQUENCE + q.Data.VarBinding.VarBindLen = uint8(len(snmpVarTempBuf.Bytes())) - 2 + q.Data.VarBinding.ObjectStart = SNMP_START_SEQUENCE + q.Data.VarBinding.ObjectLen = uint8(len(snmpVarTempBuf.Bytes())) - 4 + q.Data.VarBinding.ValueType = SNMP_TYPE_OBJECT + q.Data.VarBinding.ValueLen = 0x08 + q.Data.VarBinding.ObjectValue = 0x000001010201062b + q.Data.VarBinding.NullValue = SNMP_TYPE_NULL + q.Data.VarBinding.EndIndicator = 0x00 + + writer := new(bytes.Buffer) + binary.Write(writer, binary.LittleEndian, q) + + snmpMatcher.packets = append(snmpMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len())) + + return snmpMatcher +} + +func (t *SNMPv2Matcher) ServiceName() string { + return "SNMP" +} + +func (t *SNMPv2Matcher) PacketCount() int { + return len(t.packets) +} +func (t *SNMPv2Matcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *SNMPv2Matcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (t *SNMPv2Matcher) IsNoResponse(index int) bool { + return false +} + +func (t *SNMPv2Matcher) IsPrePacket() bool { + return false +} + +func (t *SNMPv2Matcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + r := new(bytes.Buffer) + r.Write(packet.Buffer) + + s := snmpv2{} + if err := binary.Read(r, binary.BigEndian, &s); err != nil { + return false + } + + if s.StartSeq != SNMP_START_SEQUENCE { + return false + } + + var p uint8 + reader := new(bytes.Buffer) + reader.Write(packet.Buffer) + for idx := 0; idx < 5; idx++ { + if err := binary.Read(reader, binary.BigEndian, &p); err != nil { + return false + } + if p == SNMP_TYPE_INTEGER { + break + } + p++ + } + + //finding protocol version type : 0x02 0x01 0x01 + if err := binary.Read(reader, binary.BigEndian, &p); err != nil { + return false + } + + if p == 0x01 { + if err := binary.Read(reader, binary.BigEndian, &p); err != nil { + return false + } + if p == 0x01 { + return true + } + } + + return false + +} + +func (t *SNMPv2Matcher) IsSend(port int) bool { + if port == 161 { + return true + } + return false +} diff --git a/matcher/snmp/snmpv2_test.go b/matcher/snmp/snmpv2_test.go new file mode 100644 index 0000000..ceb0dcb --- /dev/null +++ b/matcher/snmp/snmpv2_test.go @@ -0,0 +1,37 @@ +package snmp + +// +//import ( +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//func TestSNMP2(t *testing.T) { +// +// m := NewSNMPv2Matcher() +// +// conn, err := net.Dial("udp", "192.168.1.215:161") +// if err != nil { +// t.Error(err) +// return +// } +// 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("SNMP found") +// return +// } +// +// t.Error("SNMP not found") +// } +// +//} diff --git a/matcher/snmp/snmpv3.go b/matcher/snmp/snmpv3.go new file mode 100644 index 0000000..02d8a2a --- /dev/null +++ b/matcher/snmp/snmpv3.go @@ -0,0 +1,218 @@ +package snmp + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +type snmpv3GlobalData struct { + GlobalDataStartSeq uint8 + GlobalDataLen uint8 + MsgIdType uint8 + MsgIdLen uint8 + MsgId uint32 + MsgMaxSizeType uint8 + MsgMaxSizeLen uint8 + MsgMaxSize [3]uint8 + MsgFlagsType uint8 + MsgFlagsTypeLen uint8 + MsgFlags uint8 + MsgSecurityModelType uint8 + MsgSecurityModelLen uint8 + MsgSecurityModel uint8 +} + +type snmpv3MsgData struct { + MsgDataStartSeq uint8 + MsgDataLen uint8 + ContextEngineId uint16 + ContextEngineName uint16 + SnmpType uint8 + Len uint8 + RequestIdType uint8 + RequestIdLen uint8 + RequestId uint32 + ErrorStatusType uint8 + ErrorStatusLen uint8 + ErrorStatus uint8 + ErrorIndexType uint8 + ErrorIndexLen uint8 + ErrorIndex uint8 + EndSeq uint8 + EndIndicator uint8 +} + +type snmpv3 struct { + StartSeq uint8 + SeqLen uint8 + SNMPVersionType uint8 + SNMPVersionLen uint8 + SNMPVersion uint8 + MsgGlobalData snmpv3GlobalData + Unk1 uint16 + Unk2 uint16 + MsgAuthoritativeEngineId uint16 + + MsgAuthoritativeEngineBootsType uint8 + MsgAuthoritativeEngineBootsLen uint8 + MsgAuthoritativeEngineBoots uint8 + MsgAuthoritativeEngineTimeType uint8 + MsgAuthoritativeEngineTimeLen uint8 + MsgAuthoritativeEngineTime uint8 + MsgUserName uint16 + MsgAuthenticationParam uint16 + MsgPrivacyParam uint16 + MsgData snmpv3MsgData +} + +type SNMPv3Matcher struct { + packets []*packet.Packet +} + +func NewSNMPv3Matcher() *SNMPv3Matcher { + + snmpMatcher := &SNMPv3Matcher{} + + snmpTempBuf := new(bytes.Buffer) + binary.Write(snmpTempBuf, binary.BigEndian, snmpv3{}) //For getting the struct size + + snmpMsgDataTempBuf := new(bytes.Buffer) + binary.Write(snmpMsgDataTempBuf, binary.BigEndian, snmpv3MsgData{}) //For getting the struct size + + snmpGlobalTempBuf := new(bytes.Buffer) + binary.Write(snmpGlobalTempBuf, binary.BigEndian, snmpv3GlobalData{}) //For getting the struct size + + q := snmpv3{} + q.StartSeq = SNMP_START_SEQUENCE + q.SeqLen = uint8(len(snmpTempBuf.Bytes())) - 2 + q.SNMPVersionType = SNMP_TYPE_INTEGER + q.SNMPVersionLen = 0x01 + q.SNMPVersion = SNMP_PROTOCOL_VERSION_3 + q.MsgGlobalData.GlobalDataStartSeq = SNMP_START_SEQUENCE + q.MsgGlobalData.GlobalDataLen = uint8(len(snmpGlobalTempBuf.Bytes())) - 2 + q.MsgGlobalData.MsgIdType = SNMP_TYPE_INTEGER + q.MsgGlobalData.MsgIdLen = 0x04 + q.MsgGlobalData.MsgId = SNMP_MSG_ID_MAX_VALUE + q.MsgGlobalData.MsgMaxSizeType = SNMP_TYPE_INTEGER + q.MsgGlobalData.MsgMaxSizeLen = 0x03 + q.MsgGlobalData.MsgMaxSize[2] = 0xe3 + q.MsgGlobalData.MsgMaxSize[1] = 0xff + q.MsgGlobalData.MsgMaxSize[0] = 0x00 + q.MsgGlobalData.MsgFlagsType = SNMP_TYPE_STRING + q.MsgGlobalData.MsgFlagsTypeLen = 0x01 + q.MsgGlobalData.MsgFlags = 0x04 + q.MsgGlobalData.MsgSecurityModelType = SNMP_TYPE_INTEGER + q.MsgGlobalData.MsgSecurityModelLen = 0x01 + q.MsgGlobalData.MsgSecurityModel = 0x03 + q.Unk1 = 0x1004 + q.Unk2 = 0x0e30 + q.MsgAuthoritativeEngineId = SNMP_NO_DESC + q.MsgAuthoritativeEngineBootsType = SNMP_TYPE_INTEGER + q.MsgAuthoritativeEngineBootsLen = 0x01 + q.MsgAuthoritativeEngineBoots = 0x00 + q.MsgAuthoritativeEngineTimeType = SNMP_TYPE_INTEGER + q.MsgAuthoritativeEngineTimeLen = 0x01 + q.MsgAuthoritativeEngineTime = 0x00 + q.MsgUserName = SNMP_NO_DESC + q.MsgAuthenticationParam = SNMP_NO_DESC + q.MsgPrivacyParam = SNMP_NO_DESC + + q.MsgData.MsgDataStartSeq = SNMP_START_SEQUENCE + q.MsgData.MsgDataLen = uint8(len(snmpMsgDataTempBuf.Bytes())) - 2 + q.MsgData.ContextEngineId = SNMP_NO_DESC + q.MsgData.ContextEngineName = SNMP_NO_DESC + q.MsgData.SnmpType = SNMP_GET_REQUEST + q.MsgData.Len = 0x0E + q.MsgData.RequestIdType = SNMP_TYPE_INTEGER + q.MsgData.RequestIdLen = 0x04 + q.MsgData.RequestId = 0x00 // + q.MsgData.ErrorStatusType = SNMP_TYPE_INTEGER + q.MsgData.ErrorStatusLen = 0x01 + q.MsgData.ErrorStatus = 0x00 + q.MsgData.ErrorIndexType = SNMP_TYPE_INTEGER + q.MsgData.ErrorIndexLen = 0x01 + q.MsgData.ErrorIndex = 0x00 + q.MsgData.EndSeq = SNMP_END_SEQUENCE + q.MsgData.EndIndicator = 0x00 + + writer := new(bytes.Buffer) + binary.Write(writer, binary.LittleEndian, q) + + snmpMatcher.packets = append(snmpMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len())) + + return snmpMatcher +} + +func (t *SNMPv3Matcher) ServiceName() string { + return "SNMP" +} + +func (t *SNMPv3Matcher) PacketCount() int { + return len(t.packets) +} + +func (t *SNMPv3Matcher) Packet(index int) *packet.Packet { + return t.packets[index] +} + +func (t *SNMPv3Matcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} +func (t *SNMPv3Matcher) IsNoResponse(index int) bool { + return false +} + +func (t *SNMPv3Matcher) IsPrePacket() bool { + return false +} + +func (t *SNMPv3Matcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + reader := new(bytes.Buffer) + reader.Write(packet.Buffer) + + s := snmpv3{} + if err := binary.Read(reader, binary.LittleEndian, &s); err != nil { + return false + } + + if s.StartSeq != SNMP_START_SEQUENCE { + return false + } + + var p uint8 + r := new(bytes.Buffer) + r.Write(packet.Buffer) + + for { + binary.Read(r, binary.LittleEndian, &p) + + if p == SNMP_TYPE_INTEGER { + break + } + } + + binary.Read(r, binary.BigEndian, &p) + if p == 0x01 { + binary.Read(r, binary.BigEndian, &p) + if p == 0x03 { + return true + } + } + + return false + +} + +func (t *SNMPv3Matcher) IsSend(port int) bool { + if port == 161 { + return true + } + return false +} diff --git a/matcher/snmp/snmpv3_test.go b/matcher/snmp/snmpv3_test.go new file mode 100644 index 0000000..e51a31f --- /dev/null +++ b/matcher/snmp/snmpv3_test.go @@ -0,0 +1,37 @@ +package snmp + +// +//import ( +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "net" +// "testing" +//) +// +//func TestSNMP3(t *testing.T) { +// +// m := NewSNMPv3Matcher() +// +// conn, err := net.Dial("udp", "192.168.1.254:161") +// if err != nil { +// t.Error(err) +// return +// } +// 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("SNMP found") +// return +// } +// +// t.Error("SNMP not found") +// } +// +//} diff --git a/matcher/ssh/ssh.go b/matcher/ssh/ssh.go new file mode 100644 index 0000000..b7cae9c --- /dev/null +++ b/matcher/ssh/ssh.go @@ -0,0 +1,66 @@ +package ssh + +import ( + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" + "strings" +) + +type SSHMatcher struct { + sendPackets []*packet.Packet +} + +func (ssh *SSHMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + result := false + + if packet == nil || packet.Buffer == nil || packet.Len == 0 { + return result + } + + str := string(packet.Buffer) + + //fmt.Println(str) + temps := strings.Split(str, " ") + protocol := strings.Split(temps[0], "-") + //osType := temps[1] + + if 0 == strings.Compare(protocol[0], "SSH") { + majorVersion := protocol[1] + //fmt.Println(majorVersion) + if 0 == strings.Compare(majorVersion, "2.0") || 0 == strings.Compare(majorVersion, "1.0") { + result = true + } + } + + return result +} + +func (ssh *SSHMatcher) PacketCount() int { + return len(ssh.sendPackets) +} + +func (ssh *SSHMatcher) Packet(index int) *packet.Packet { + return ssh.sendPackets[index] +} + +func (ssh *SSHMatcher) ServiceName() string { + return "SSH" +} + +func (ssh *SSHMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (ssh *SSHMatcher) IsNoResponse(index int) bool { + return false +} + +func (ssh *SSHMatcher) IsPrePacket() bool { + return true +} + +func NewSSHMatcher() *SSHMatcher { + r := SSHMatcher{} + + return &r +} diff --git a/matcher/ssh/ssh_test.go b/matcher/ssh/ssh_test.go new file mode 100644 index 0000000..17bf802 --- /dev/null +++ b/matcher/ssh/ssh_test.go @@ -0,0 +1,33 @@ +package ssh + +//import ( +// "fmt" +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +//func TestSSHMatcher_Match(t *testing.T) { +// +// port := types.NewPort("22", types.NewHost("192.168.1.103"), types.TYPE_TCP) +// ssh := NewSSHMatcher() +// +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// client, _ := net.Dial("tcp", ipport) +// +// defer client.Close() +// +// bytes := make([]byte, 512) +// +// l, _ := client.Read(bytes) +// +// fmt.Println(bytes) +// +// b := ssh.Match(0, packet.NewPacket(bytes, l), nil) +// +// fmt.Println(b) +// +//} diff --git a/matcher/telnet/telnet.go b/matcher/telnet/telnet.go new file mode 100644 index 0000000..466051b --- /dev/null +++ b/matcher/telnet/telnet.go @@ -0,0 +1,79 @@ +package telnet + +import ( + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + DO = 0xfd + WONT = 0x4b + WILL = 0xfb + DONT = 0xfe + CMD = 0xff +) + +type TelnetMatcher struct { + sendPackets []*packet.Packet +} + +func (tel *TelnetMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + result := false + + if packet == nil || packet.Buffer == nil || packet.Len == 0 { + return result + } + + buf := make([]byte, 0, 0) + count := 0 + + for i := 0; i < len(packet.Buffer); i++ { + if packet.Buffer[i] > 0 { + buf = append(buf, packet.Buffer[i]) + } else if count > 2 { + break + } else { + count++ + } + } + + for idx := 0; idx < len(buf); idx += 3 { + if buf[idx] == CMD && (buf[idx+1] == DO || buf[idx+1] == WONT || buf[idx+1] == WILL || buf[idx+1] == DONT) { + result = true + } else { + result = false + } + } + + return result +} + +func (tel *TelnetMatcher) PacketCount() int { + return len(tel.sendPackets) +} + +func (tel *TelnetMatcher) Packet(index int) *packet.Packet { + return tel.sendPackets[index] +} + +func (tel *TelnetMatcher) ServiceName() string { + return "Telnet" +} + +func (tel *TelnetMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} + +func (tel *TelnetMatcher) IsNoResponse(index int) bool { + return false +} + +func (tel *TelnetMatcher) IsPrePacket() bool { + return true +} + +func NewTelnetMatcher() *TelnetMatcher { + r := TelnetMatcher{} + + return &r +} diff --git a/matcher/telnet/telnet_test.go b/matcher/telnet/telnet_test.go new file mode 100644 index 0000000..445df95 --- /dev/null +++ b/matcher/telnet/telnet_test.go @@ -0,0 +1,33 @@ +package telnet + +//import ( +// "fmt" +// "loafle.com/overflow/collector/core/scan/service/matcher/packet" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +//func TestTelnetMatcher_Match(t *testing.T) { +// +// port := types.NewPort("23", types.NewHost("192.168.1.210"), types.TYPE_TCP) +// telnet := NewTelnetMatcher() +// +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// client, _ := net.Dial("tcp", ipport) +// +// defer client.Close() +// +// bytes := make([]byte, 512) +// +// l, _ := client.Read(bytes) +// +// fmt.Println("length :", l) +// fmt.Println(bytes) +// +// b := telnet.Match(0, packet.NewPacket(bytes, l), nil) +// +// fmt.Println(b) +//} diff --git a/matcher/wmi/wmi.go b/matcher/wmi/wmi.go new file mode 100644 index 0000000..9ad16b1 --- /dev/null +++ b/matcher/wmi/wmi.go @@ -0,0 +1,250 @@ +package wmi + +import ( + "bytes" + "encoding/binary" + "loafle.com/overflow/commons_go/matcher/packet" + "loafle.com/overflow/commons_go/model/scaninfo" +) + +const ( + PDU_BIND = 11 + PDU_BIND_ACK = 12 + PDU_REQ = 0 + PDU_RESP = 2 + + WMI_CALL_ID_1 = 0x95 + WMI_CALL_ID_2 = 0x96 +) + +type WMIMatcher struct { + sendPackets []*packet.Packet +} + +func (w *WMIMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + + if packet == nil { + return false + } + + buf := new(bytes.Buffer) + buf.Write(packet.Buffer) + + wmiRecv := DCERPC_DEFAULT{} + + binary.Read(buf, binary.LittleEndian, &wmiRecv) + + switch index { + case 0: + if wmiRecv.Call_id != WMI_CALL_ID_1 { + return false + } + + if wmiRecv.Ptype != PDU_BIND_ACK { + return false + } + + return true + case 1: + + if wmiRecv.Call_id != WMI_CALL_ID_2 { + return false + } + + if wmiRecv.Ptype != PDU_RESP { + return false + } + + return true + } + + return false +} + +func (w *WMIMatcher) PacketCount() int { + return len(w.sendPackets) +} +func (w *WMIMatcher) Packet(index int) *packet.Packet { + return w.sendPackets[index] +} +func (w *WMIMatcher) ServiceName() string { + return "WMI" +} + +func (w *WMIMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool { + return false +} +func (w *WMIMatcher) IsNoResponse(index int) bool { + + return false +} + +func (w *WMIMatcher) IsPrePacket() bool { + return true +} + +func NewWMIMatcher() *WMIMatcher { + + wm := WMIMatcher{} + + ds1 := DCERPC_DEFAULT{ + Rpc_ver: 5, + Rpc_ver_minor: 0, + Ptype: PDU_BIND, + Flags: 0x03, + Drep: 0x10, + Frag_len: 16 + 56, + Auth_len: 0, + Call_id: WMI_CALL_ID_1, + } + + ds2 := DCERPC_DEFAULT{ + Rpc_ver: 5, + Rpc_ver_minor: 0, + Ptype: PDU_REQ, + Flags: 0x03, + Drep: 0x10, + Frag_len: 16 + 8, + Auth_len: 0, + Call_id: WMI_CALL_ID_2, + } + + ioxidr := DCERPC_IOXIDResolver{ + MaxXmitFrag: 0x16d0, + MaxRecvFrag: 0x16d0, + + AssocGroup: 0, + NumCtxItem: 1, + + ContextId: 0, + NumTransItem: 1, + + //interfaces + + InterfaceVer: 0, + InterfaceVerMinor: 0, + + //transSyntax + + TransSyntaxVer: 2, + } + + ioxidr.Interfaces[0] = 0xc4 + ioxidr.Interfaces[1] = 0xfe + ioxidr.Interfaces[2] = 0xfc + ioxidr.Interfaces[3] = 0x99 + + ioxidr.Interfaces[4] = 0x60 + ioxidr.Interfaces[5] = 0x52 + + ioxidr.Interfaces[6] = 0x1b + ioxidr.Interfaces[7] = 0x10 + + ioxidr.Interfaces[8] = 0xbb + ioxidr.Interfaces[9] = 0xcb + + ioxidr.Interfaces[10] = 0x00 + ioxidr.Interfaces[11] = 0xaa + ioxidr.Interfaces[12] = 0x00 + ioxidr.Interfaces[13] = 0x21 + ioxidr.Interfaces[14] = 0x34 + ioxidr.Interfaces[15] = 0x7a + + ioxidr.TransSyntax[0] = 0x04 + ioxidr.TransSyntax[1] = 0x5d + ioxidr.TransSyntax[2] = 0x88 + ioxidr.TransSyntax[3] = 0x8a + + ioxidr.TransSyntax[4] = 0xeb + ioxidr.TransSyntax[5] = 0x1c + + ioxidr.TransSyntax[6] = 0xc9 + ioxidr.TransSyntax[7] = 0x11 + + ioxidr.TransSyntax[8] = 0x9f + ioxidr.TransSyntax[9] = 0xe8 + + ioxidr.TransSyntax[10] = 0x08 + ioxidr.TransSyntax[11] = 0x00 + ioxidr.TransSyntax[12] = 0x2b + ioxidr.TransSyntax[13] = 0x10 + ioxidr.TransSyntax[14] = 0x48 + ioxidr.TransSyntax[15] = 0x60 + + da := DCERPC_ALIVE{ + AllocHint: 0, + ContextId: 0, + OpNum: 3, + } + + buf1 := new(bytes.Buffer) + + binary.Write(buf1, binary.LittleEndian, ds1) + ds1Bytes := buf1.Bytes() + + buf2 := new(bytes.Buffer) + + binary.Write(buf2, binary.LittleEndian, ds2) + ds2Bytes := buf2.Bytes() + + buf3 := new(bytes.Buffer) + + binary.Write(buf3, binary.LittleEndian, ioxidr) + ioxidrBytes := buf3.Bytes() + + buf4 := new(bytes.Buffer) + + binary.Write(buf4, binary.LittleEndian, da) + daBytes := buf4.Bytes() + + firstByte := make([]byte, len(ds1Bytes)+len(ioxidrBytes)) + + copy(firstByte[0:], ds1Bytes) + copy(firstByte[len(ds1Bytes):], ioxidrBytes) + + secondByte := make([]byte, len(ds2Bytes)+len(daBytes)) + + copy(secondByte[0:], ds2Bytes) + copy(secondByte[len(ds2Bytes):], daBytes) + + wm.sendPackets = append(wm.sendPackets, packet.NewPacket(firstByte, len(ds1Bytes)+len(ioxidrBytes))) + wm.sendPackets = append(wm.sendPackets, packet.NewPacket(secondByte, len(ds2Bytes)+len(daBytes))) + + return &wm + +} + +type DCERPC_DEFAULT struct { + Rpc_ver uint8 + Rpc_ver_minor uint8 + Ptype uint8 + Flags uint8 + Drep uint32 + Frag_len uint16 + Auth_len uint16 + Call_id uint32 +} + +type DCERPC_ALIVE struct { + AllocHint uint32 + ContextId uint16 + OpNum uint16 +} + +type DCERPC_IOXIDResolver struct { + MaxXmitFrag uint16 + MaxRecvFrag uint16 + AssocGroup uint32 + NumCtxItem uint8 + UnknownCode [3]uint8 + + ContextId uint16 + NumTransItem uint8 + UnknownCode2 uint8 + + Interfaces [16]uint8 + InterfaceVer uint16 + InterfaceVerMinor uint16 + TransSyntax [16]uint8 + TransSyntaxVer uint32 +} diff --git a/matcher/wmi/wmi_test.go b/matcher/wmi/wmi_test.go new file mode 100644 index 0000000..6fd03a3 --- /dev/null +++ b/matcher/wmi/wmi_test.go @@ -0,0 +1,51 @@ +package wmi + +//import ( +// "fmt" +// "loafle.com/overflow/collector/discovery/scan/matcher/packet" +// "loafle.com/overflow/collector/discovery/scan/matcher/scaninfo" +// "loafle.com/overflow/collector/discovery/types" +// "net" +// "testing" +//) +// +//func TestWMI(t *testing.T) { +// +// lm := NewWMIMatcher() +// +// port := types.NewPort("135", types.NewHost("192.168.1.1"), types.TYPE_TCP) +// scanInfo := scaninfo.NewServiceScanInfo(port) +// var ipport string +// ipport = port.Host.Ip + ":" + string(port.Port) +// +// fmt.Println(ipport) +// client, _ := net.Dial("tcp", ipport) +// +// defer client.Close() +// +// fmt.Println(lm.PacketCount()) +// +// for ii := 0; ii < lm.PacketCount(); ii++ { +// +// pack := lm.Packet(ii) +// +// fmt.Println(pack) +// +// client.Write(pack.Buffer) +// +// bytes := make([]byte, 1024) +// +// read, _ := client.Read(bytes) +// +// //fmt.Println(bytes) +// +// b := lm.Match(ii, packet.NewPacket(bytes, read), scanInfo) +// +// if b { +// fmt.Println("Good") +// } +// +// } +// +// t.Log(scanInfo) +//} diff --git a/model/scaninfo/scaninfo.go b/model/scaninfo/scaninfo.go new file mode 100644 index 0000000..8aefc57 --- /dev/null +++ b/model/scaninfo/scaninfo.go @@ -0,0 +1,7 @@ +package scaninfo + +type ServiceScanInfo interface { + SetHistory(history string) + GetPort() string + GetIP() string +} diff --git a/model/timestamp/timestamp.go b/model/timestamp/timestamp.go new file mode 100644 index 0000000..6a465d0 --- /dev/null +++ b/model/timestamp/timestamp.go @@ -0,0 +1,37 @@ +package timestamp + +import ( + "fmt" + "strconv" + "time" +) + +type Timestamp time.Time + +func (t Timestamp) MarshalJSON() ([]byte, error) { + ts := time.Time(t).Unix() + stamp := fmt.Sprint(ts * 1000) + return []byte(stamp), nil +} + +func (t *Timestamp) UnmarshalJSON(b []byte) error { + ts, err := strconv.Atoi(string(b)) + if err != nil { + return err + } + *t = Timestamp(time.Unix(int64(ts)/1000, 0)) + + return nil +} + +func (t Timestamp) String() string { + return time.Time(t).String() +} + +func Now() Timestamp { + return Timestamp(time.Now()) +} + +func Date(year int, month time.Month, day int) Timestamp { + return Timestamp(time.Date(year, month, day, 0, 0, 0, 0, time.UTC)) +}