zgrab2/modules/fox/fox.go

137 lines
5.4 KiB
Go

package fox
import (
"bytes"
"encoding/hex"
"errors"
"io"
"net"
"strconv"
"strings"
"github.com/zmap/zgrab2"
)
const (
// ORIGINAL_QUERY is the hex encoding of the query that will be sent to each server.
ORIGINAL_QUERY = "666f7820612031202d3120666f782068656c6c6f0a7b0a" +
"666f782e76657273696f6e3d733a312e300a69643d693a310a686f73744e" +
"616d653d733a7870766d2d306f6d64633031786d790a686f737441646472" +
"6573733d733a3139322e3136382e312e3132350a6170702e6e616d653d73" +
"3a576f726b62656e63680a6170702e76657273696f6e3d733a332e372e34" +
"340a766d2e6e616d653d733a4a61766120486f7453706f7428544d292053" +
"657276657220564d0a766d2e76657273696f6e3d733a32302e342d623032" +
"0a6f732e6e616d653d733a57696e646f77732058500a6f732e7665727369" +
"6f6e3d733a352e310a6c616e673d733a656e0a74696d655a6f6e653d733a" +
"416d65726963612f4c6f735f416e67656c65733b2d32383830303030303b" +
"333630303030303b30323a30303a30302e3030302c77616c6c2c6d617263" +
"682c382c6f6e206f722061667465722c73756e6461792c756e646566696e" +
"65643b30323a30303a30302e3030302c77616c6c2c6e6f76656d6265722c" +
"312c6f6e206f722061667465722c73756e6461792c756e646566696e6564" +
"0a686f737449643d733a57696e2d393943422d443439442d353434322d30" +
"3742420a766d557569643d733a38623533306263382d373663352d343133" +
"392d613265612d3066616264333934643330350a6272616e6449643d733a" +
"76796b6f6e0a7d3b3b0a"
// RESPONSE_PREFIX is the prefix that will identify a Fox service.
RESPONSE_PREFIX = "fox a 0 -1 fox hello"
)
var queryBytes []byte
func init() {
var err error
queryBytes, err = hex.DecodeString(ORIGINAL_QUERY)
if err != nil {
panic("Could not decode Fox query")
}
}
// GetFoxBanner sends the static query and reads the response, filling out the logStruct with any fields that are
// present. The IsFox field will identify whether a Fox service was detected, regardless of whether an error was
// returned.
func GetFoxBanner(logStruct *FoxLog, connection net.Conn) error {
bytesWritten, err := connection.Write(queryBytes)
if bytesWritten != len(queryBytes) {
return errors.New("Unable to write all Fox query bytes...")
}
if err != nil {
return err
}
data, err := zgrab2.ReadAvailable(connection)
if err != nil && err != io.EOF {
return err
}
responseString := string(data)
output := bytes.Split([]byte(responseString), []byte{0x0a})
var (
colon = []byte(":")
semi = []byte(";")
)
b := func(s string) []byte {
return []byte(s)
}
s := func(b []byte) string {
return string(b)
}
if strings.HasPrefix(responseString, RESPONSE_PREFIX) {
logStruct.IsFox = true
for _, value := range output {
if bytes.HasPrefix(value, []byte("fox.version")) && bytes.Contains(value, colon) {
logStruct.Version = string(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("id")) && bytes.Contains(value, colon) {
id, err := strconv.ParseUint(string(bytes.Split(value, colon)[1]), 10, 32)
if err != nil {
return err
}
logStruct.Id = uint32(id)
} else if bytes.HasPrefix(value, b("hostAddress")) && bytes.Contains(value, colon) {
// TODO: What if this is IPv6? Or, more generally, what if any of these contain a colon?
logStruct.HostAddress = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("hostName")) && bytes.Contains(value, colon) {
logStruct.Hostname = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("app.name")) && bytes.Contains(value, colon) {
logStruct.AppName = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("app.version")) && bytes.Contains(value, colon) {
logStruct.AppVersion = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("vm.name")) && bytes.Contains(value, colon) {
logStruct.VMName = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("vm.version")) && bytes.Contains(value, colon) {
logStruct.VMVersion = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("os.name")) && bytes.Contains(value, colon) {
logStruct.OSName = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("os.version")) && bytes.Contains(value, colon) {
logStruct.OSVersion = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("station.name")) && bytes.Contains(value, colon) {
logStruct.StationName = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("lang")) && bytes.Contains(value, colon) {
logStruct.Language = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("timeZone")) && bytes.Contains(value, colon) {
timeZone := bytes.Split(value, colon)[1]
if bytes.Contains(timeZone, semi) {
timeZone = bytes.Split(timeZone, semi)[0]
}
logStruct.TimeZone = s(timeZone)
} else if bytes.HasPrefix(value, b("hostId")) && bytes.Contains(value, colon) {
logStruct.HostId = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("vmUuid")) && bytes.Contains(value, colon) {
logStruct.VMUuid = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("brandId")) && bytes.Contains(value, colon) {
logStruct.BrandId = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("sysInfo")) && bytes.Contains(value, colon) {
logStruct.SysInfo = s(bytes.Split(value, colon)[1])
} else if bytes.HasPrefix(value, b("authAgentTypeSpecs")) && bytes.Contains(value, colon) {
logStruct.AuthAgentType = s(bytes.Split(value, colon)[1])
}
}
}
return nil
}