mirror of
https://github.com/sairson/Yasso.git
synced 2026-02-03 18:43:38 +08:00
594 lines
16 KiB
Go
594 lines
16 KiB
Go
package example
|
|
|
|
import (
|
|
"bytes"
|
|
crand "crypto/rand"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func Test(t *testing.T) {
|
|
res, _, err := smb2("192.168.248.224", 445, 1*time.Second)
|
|
if err != nil || res["ntlmssp.Version"] == "" {
|
|
return
|
|
} else {
|
|
banner := fmt.Sprintf("Version:%s||DNSComputer:%s||TargetName:%s||NetbiosComputer:%s",
|
|
res["ntlmssp.Version"],
|
|
res["ntlmssp.DNSComputer"],
|
|
res["ntlmssp.TargetName"],
|
|
res["ntlmssp.NetbiosComputer"],
|
|
)
|
|
fmt.Println(banner)
|
|
return
|
|
}
|
|
}
|
|
|
|
// smb2 from https://github.com/RumbleDiscovery/rumble-tools/blob/main/cmd/rumble-smb2-sessions/main.go
|
|
func smb2(host string, port int, timeout time.Duration) (map[string]string, []byte, error) {
|
|
// SMB1NegotiateProtocolRequest is a SMB1 request that advertises support for SMB2
|
|
var smb1NegotiateProtocolRequest = []byte{
|
|
0x00, 0x00, 0x00, 0xd4, 0xff, 0x53, 0x4d, 0x42,
|
|
0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x43, 0xc8,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x02,
|
|
0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
|
|
0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52,
|
|
0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02,
|
|
0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f, 0x46,
|
|
0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52,
|
|
0x4b, 0x53, 0x20, 0x31, 0x2e, 0x30, 0x33, 0x00,
|
|
0x02, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f,
|
|
0x46, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
|
|
0x52, 0x4b, 0x53, 0x20, 0x33, 0x2e, 0x30, 0x00,
|
|
0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31,
|
|
0x2e, 0x30, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e,
|
|
0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x44,
|
|
0x4f, 0x53, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
|
|
0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4c, 0x41,
|
|
0x4e, 0x4d, 0x41, 0x4e, 0x32, 0x2e, 0x31, 0x00,
|
|
0x02, 0x53, 0x61, 0x6d, 0x62, 0x61, 0x00, 0x02,
|
|
0x4e, 0x54, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
|
|
0x4e, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4e,
|
|
0x54, 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31,
|
|
0x32, 0x00, 0x02, 0x53, 0x4d, 0x42, 0x20, 0x32,
|
|
0x2e, 0x30, 0x30, 0x32, 0x00, 0x02, 0x53, 0x4d,
|
|
0x42, 0x20, 0x32, 0x2e, 0x3f, 0x3f, 0x3f, 0x00,
|
|
}
|
|
fmt.Println(string(smb1NegotiateProtocolRequest))
|
|
info := make(map[string]string)
|
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), timeout)
|
|
if err != nil {
|
|
return info, []byte{}, err
|
|
}
|
|
err = SMBSendData(conn, smb1NegotiateProtocolRequest, timeout)
|
|
if err != nil {
|
|
return info, []byte{}, err
|
|
}
|
|
|
|
data, err := SMBReadFrame(conn, timeout)
|
|
if err != nil {
|
|
return info, []byte{}, err
|
|
}
|
|
|
|
err = SMBSendData(conn, SMB2NegotiateProtocolRequest(host), timeout)
|
|
if err != nil {
|
|
return info, []byte{}, err
|
|
}
|
|
|
|
data, _ = SMBReadFrame(conn, timeout)
|
|
SMB2ExtractFieldsFromNegotiateReply(data, info)
|
|
|
|
// SMB2SessionSetupNTLMSSP is a SMB2 SessionSetup NTLMSSP request
|
|
var smb2SessionSetupNTLMSSP = []byte{
|
|
0x00, 0x00, 0x00, 0xa2, 0xfe, 0x53, 0x4d, 0x42,
|
|
0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x01,
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x58, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x60, 0x48, 0x06, 0x06,
|
|
0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x3e,
|
|
0x30, 0x3c, 0xa0, 0x0e, 0x30, 0x0c, 0x06, 0x0a,
|
|
0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
|
|
0x02, 0x0a, 0xa2, 0x2a, 0x04, 0x28, 0x4e, 0x54,
|
|
0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00,
|
|
0x00, 0x00, 0x97, 0x82, 0x08, 0xe2, 0x00, 0x00,
|
|
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0a, 0x00,
|
|
0xba, 0x47, 0x00, 0x00, 0x00, 0x0f,
|
|
}
|
|
|
|
setup := make([]byte, len(smb2SessionSetupNTLMSSP))
|
|
copy(setup, smb2SessionSetupNTLMSSP)
|
|
|
|
// Set the ProcessID
|
|
binary.LittleEndian.PutUint16(setup[4+32:], 0xfeff)
|
|
|
|
err = SMBSendData(conn, setup, timeout)
|
|
if err != nil {
|
|
return info, []byte{}, err
|
|
}
|
|
|
|
data, err = SMBReadFrame(conn, timeout)
|
|
SMB2ExtractSIDFromSessionSetupReply(data, info)
|
|
SMBExtractFieldsFromSecurityBlob(data, info)
|
|
|
|
return info, data, err
|
|
}
|
|
|
|
// RandomBytes generates a random byte sequence of the requested length
|
|
func RandomBytes(numBytes int) []byte {
|
|
randBytes := make([]byte, numBytes)
|
|
err := binary.Read(crand.Reader, binary.BigEndian, &randBytes)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return randBytes
|
|
}
|
|
|
|
// SMBReadFrame reads the netBios header then the full response
|
|
func SMBReadFrame(conn net.Conn, t time.Duration) ([]byte, error) {
|
|
timeout := time.Now().Add(time.Duration(t) * time.Second)
|
|
res := []byte{}
|
|
nbh := make([]byte, 4)
|
|
|
|
err := conn.SetReadDeadline(timeout)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
// Read the NetBIOS header
|
|
n, err := conn.Read(nbh[:])
|
|
if err != nil {
|
|
// Return if EOF is reached
|
|
if err == io.EOF {
|
|
return res, nil
|
|
}
|
|
|
|
// Return if timeout is reached
|
|
if err, ok := err.(net.Error); ok && err.Timeout() {
|
|
return res, nil
|
|
}
|
|
|
|
// If we have data and received an error, it was probably a reset
|
|
if len(res) > 0 {
|
|
return res, nil
|
|
}
|
|
|
|
return res, err
|
|
}
|
|
|
|
if n != 4 {
|
|
return res, nil
|
|
}
|
|
|
|
res = append(res[:], nbh[:n]...)
|
|
dlen := binary.BigEndian.Uint32(nbh[:]) & 0x00ffffff
|
|
buf := make([]byte, dlen)
|
|
n, err = conn.Read(buf[:])
|
|
if err != nil {
|
|
// Return if EOF is reached
|
|
if err == io.EOF {
|
|
return res, nil
|
|
}
|
|
|
|
// Return if timeout is reached
|
|
if err, ok := err.(net.Error); ok && err.Timeout() {
|
|
return res, nil
|
|
}
|
|
|
|
// If we have data and received an error, it was probably a reset
|
|
if len(res) > 0 {
|
|
return res, nil
|
|
}
|
|
|
|
return res, err
|
|
}
|
|
res = append(res[:], buf[:n]...)
|
|
return res, nil
|
|
}
|
|
|
|
// SMB2ExtractFieldsFromNegotiateReply extracts useful fields from the SMB2 negotiate response
|
|
func SMB2ExtractFieldsFromNegotiateReply(blob []byte, info map[string]string) {
|
|
|
|
smbOffset := bytes.Index(blob, []byte{0xfe, 'S', 'M', 'B'})
|
|
if smbOffset < 0 {
|
|
return
|
|
}
|
|
|
|
data := blob[smbOffset:]
|
|
|
|
// Basic sanity check
|
|
if len(data) < (64 + 8 + 16 + 36) {
|
|
return
|
|
}
|
|
|
|
switch binary.LittleEndian.Uint16(data[64+2:]) {
|
|
case 0:
|
|
info["smb.Signing"] = "disabled"
|
|
case 1:
|
|
info["smb.Signing"] = "enabled"
|
|
case 2, 3:
|
|
info["smb.Signing"] = "required"
|
|
}
|
|
|
|
info["smb.Dialect"] = fmt.Sprintf("0x%.4x", binary.LittleEndian.Uint16(data[64+4:]))
|
|
//info["smb.GUID"] = uuid.FromBytesOrNil(data[64+8 : 64+8+16]).String()
|
|
info["smb.Capabilities"] = fmt.Sprintf("0x%.8x", binary.LittleEndian.Uint32(data[64+8+16:]))
|
|
|
|
negCtxCount := int(binary.LittleEndian.Uint16(data[64+6:]))
|
|
negCtxOffset := int(binary.LittleEndian.Uint32(data[64+8+16+36:]))
|
|
if negCtxCount == 0 || negCtxOffset == 0 || negCtxOffset+(negCtxCount*8) > len(data) {
|
|
return
|
|
}
|
|
|
|
negCtxData := data[negCtxOffset:]
|
|
idx := 0
|
|
for {
|
|
if idx+8 > len(negCtxData) {
|
|
break
|
|
}
|
|
negType := int(binary.LittleEndian.Uint16(negCtxData[idx:]))
|
|
negLen := int(binary.LittleEndian.Uint16(negCtxData[idx+2:]))
|
|
idx += 8
|
|
|
|
if idx+negLen > len(negCtxData) {
|
|
break
|
|
}
|
|
negData := negCtxData[idx : idx+negLen]
|
|
|
|
SMB2ParseNegotiateContext(negType, negData, info)
|
|
|
|
// Move the index to the next context
|
|
idx += negLen
|
|
// Negotiate Contexts are aligned on 64-bit boundaries
|
|
for idx%8 != 0 {
|
|
idx++
|
|
}
|
|
}
|
|
}
|
|
|
|
// SMB2ParseNegotiateContext decodes fields from the SMB2 Negotiate Context values
|
|
func SMB2ParseNegotiateContext(t int, data []byte, info map[string]string) {
|
|
switch t {
|
|
case 1:
|
|
// SMB2_PREAUTH_INTEGRITY_CAPABILITIES
|
|
if len(data) < 6 {
|
|
return
|
|
}
|
|
hashCount := int(binary.LittleEndian.Uint16(data[:]))
|
|
// MUST only be one in responses
|
|
if hashCount != 1 {
|
|
return
|
|
}
|
|
hashSaltLen := int(binary.LittleEndian.Uint16(data[2:]))
|
|
hashType := int(binary.LittleEndian.Uint16(data[4:]))
|
|
hashName := "sha512"
|
|
if hashType != 1 {
|
|
hashName = fmt.Sprintf("unknown-%d", hashType)
|
|
}
|
|
info["smb.HashAlg"] = hashName
|
|
info["smb.HashSaltLen"] = fmt.Sprintf("%d", hashSaltLen)
|
|
|
|
case 2:
|
|
// SMB2_ENCRYPTION_CAPABILITIES
|
|
if len(data) < 4 {
|
|
return
|
|
}
|
|
cipherCount := int(binary.LittleEndian.Uint16(data[:]))
|
|
if len(data) < 2+(2*cipherCount) {
|
|
return
|
|
}
|
|
// MUST only be one in responses
|
|
if cipherCount != 1 {
|
|
return
|
|
}
|
|
cipherList := []string{}
|
|
for i := 0; i < cipherCount; i++ {
|
|
cipherID := int(binary.LittleEndian.Uint16(data[2+(i*2):]))
|
|
cipherName := ""
|
|
switch cipherID {
|
|
case 1:
|
|
cipherName = "aes-128-ccm"
|
|
case 2:
|
|
cipherName = "aes-128-gcm"
|
|
default:
|
|
cipherName = fmt.Sprintf("unknown-%d", cipherID)
|
|
}
|
|
cipherList = append(cipherList, cipherName)
|
|
}
|
|
|
|
info["smb.CipherAlg"] = strings.Join(cipherList, "\t")
|
|
|
|
case 3:
|
|
// SMB2_COMPRESSION_CAPABILITIES
|
|
if len(data) < 10 {
|
|
return
|
|
}
|
|
compCount := int(binary.LittleEndian.Uint16(data[:]))
|
|
if len(data) < 2+2+4+(2*compCount) {
|
|
return
|
|
}
|
|
// MUST only be one in responses
|
|
if compCount != 1 {
|
|
return
|
|
}
|
|
compList := []string{}
|
|
for i := 0; i < compCount; i++ {
|
|
compID := int(binary.LittleEndian.Uint16(data[8+(i*2):]))
|
|
compName := ""
|
|
switch compID {
|
|
case 0:
|
|
compName = "none"
|
|
case 1:
|
|
compName = "lznt1"
|
|
case 2:
|
|
compName = "lz77"
|
|
case 3:
|
|
compName = "lz77+huff"
|
|
case 4:
|
|
compName = "patternv1"
|
|
default:
|
|
compName = fmt.Sprintf("unknown-%d", compID)
|
|
}
|
|
compList = append(compList, compName)
|
|
}
|
|
info["smb.CompressionFlags"] = fmt.Sprintf("0x%.4x", binary.LittleEndian.Uint32(data[4:]))
|
|
info["smb.CompressionAlg"] = strings.Join(compList, "\t")
|
|
}
|
|
}
|
|
|
|
// SMBSendData writes a SMB request to a socket
|
|
func SMBSendData(conn net.Conn, data []byte, timeout time.Duration) error {
|
|
err := conn.SetWriteDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
n, err := conn.Write(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = n
|
|
|
|
return nil
|
|
}
|
|
|
|
// SMB2ExtractSIDFromSessionSetupReply tries to extract the SessionID and Signature from a SMB2 reply
|
|
func SMB2ExtractSIDFromSessionSetupReply(blob []byte, info map[string]string) {
|
|
smbOffset := bytes.Index(blob, []byte{0xfe, 'S', 'M', 'B'})
|
|
if smbOffset < 0 {
|
|
return
|
|
}
|
|
|
|
smbData := blob[smbOffset:]
|
|
if len(smbData) < 48 {
|
|
return
|
|
}
|
|
|
|
status := binary.LittleEndian.Uint32(smbData[8:])
|
|
info["smb.Status"] = fmt.Sprintf("0x%.8x", status)
|
|
|
|
sessID := binary.LittleEndian.Uint64(smbData[40:])
|
|
info["smb.SessionID"] = fmt.Sprintf("0x%.16x", sessID)
|
|
|
|
if len(smbData) >= 64 {
|
|
sigData := hex.EncodeToString(smbData[48:64])
|
|
if sigData != "00000000000000000000000000000000" {
|
|
info["smb.Signature"] = sigData
|
|
}
|
|
}
|
|
}
|
|
|
|
// SMBExtractValueFromOffset peels a field out of a SMB buffer
|
|
func SMBExtractValueFromOffset(blob []byte, idx int) ([]byte, int, error) {
|
|
res := []byte{}
|
|
|
|
if len(blob) < (idx + 6) {
|
|
return res, idx, fmt.Errorf("data truncated")
|
|
}
|
|
|
|
len1 := binary.LittleEndian.Uint16(blob[idx:])
|
|
idx += 2
|
|
|
|
// len2 := binary.LittleEndian.Uint16(blob[idx:])
|
|
idx += 2
|
|
|
|
off := binary.LittleEndian.Uint32(blob[idx:])
|
|
idx += 4
|
|
|
|
// Allow zero length values
|
|
if len1 == 0 {
|
|
return res, idx, nil
|
|
}
|
|
|
|
if len(blob) < int(off+uint32(len1)) {
|
|
return res, idx, fmt.Errorf("data value truncated")
|
|
}
|
|
|
|
res = append(res, blob[off:off+uint32(len1)]...)
|
|
return res, idx, nil
|
|
}
|
|
|
|
// SMBExtractFieldsFromSecurityBlob extracts fields from the NTLMSSP response
|
|
func SMBExtractFieldsFromSecurityBlob(blob []byte, info map[string]string) {
|
|
var err error
|
|
|
|
ntlmsspOffset := bytes.Index(blob, []byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00, 0x02, 0x00, 0x00, 0x00})
|
|
if ntlmsspOffset < 0 {
|
|
return
|
|
}
|
|
|
|
data := blob[ntlmsspOffset:]
|
|
|
|
// Basic sanity check
|
|
if len(data) < (12 + 6 + 12 + 8 + 6 + 8) {
|
|
return
|
|
}
|
|
|
|
idx := 12
|
|
|
|
targetName, idx, err := SMBExtractValueFromOffset(data, idx)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Negotiate Flags
|
|
negotiateFlags := binary.LittleEndian.Uint32(data[idx:])
|
|
info["ntlmssp.NegotiationFlags"] = fmt.Sprintf("0x%.8x", negotiateFlags)
|
|
idx += 4
|
|
|
|
// NTLM Server Challenge
|
|
idx += 8
|
|
|
|
// Reserved
|
|
idx += 8
|
|
|
|
// Target Info
|
|
targetInfo, idx, err := SMBExtractValueFromOffset(data, idx)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Version
|
|
versionMajor := uint8(data[idx])
|
|
idx++
|
|
|
|
versionMinor := uint8(data[idx])
|
|
idx++
|
|
|
|
versionBuild := binary.LittleEndian.Uint16(data[idx:])
|
|
idx += 2
|
|
|
|
ntlmRevision := binary.BigEndian.Uint32(data[idx:])
|
|
|
|
// macOS reverses the endian order of this field for some reason
|
|
if ntlmRevision == 251658240 {
|
|
ntlmRevision = binary.LittleEndian.Uint32(data[idx:])
|
|
}
|
|
|
|
info["ntlmssp.Version"] = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionBuild)
|
|
info["ntlmssp.NTLMRevision"] = fmt.Sprintf("%d", ntlmRevision)
|
|
info["ntlmssp.TargetName"] = TrimName(string(targetName))
|
|
|
|
idx = 0
|
|
for {
|
|
if idx+4 > len(targetInfo) {
|
|
break
|
|
}
|
|
|
|
attrType := binary.LittleEndian.Uint16(targetInfo[idx:])
|
|
idx += 2
|
|
|
|
// End of List
|
|
if attrType == 0 {
|
|
break
|
|
}
|
|
|
|
attrLen := binary.LittleEndian.Uint16(targetInfo[idx:])
|
|
idx += 2
|
|
|
|
if idx+int(attrLen) > len(targetInfo) {
|
|
// log.Printf("too short: %d/%d", idx+int(attrLen), len(targetInfo))
|
|
break
|
|
}
|
|
|
|
attrVal := targetInfo[idx : idx+int(attrLen)]
|
|
idx += int(attrLen)
|
|
|
|
switch attrType {
|
|
case 1:
|
|
info["ntlmssp.NetbiosComputer"] = TrimName(string(attrVal))
|
|
case 2:
|
|
info["ntlmssp.NetbiosDomain"] = TrimName(string(attrVal))
|
|
case 3:
|
|
info["ntlmssp.DNSComputer"] = TrimName(string(attrVal))
|
|
case 4:
|
|
info["ntlmssp.DNSDomain"] = TrimName(string(attrVal))
|
|
case 7:
|
|
ts := binary.LittleEndian.Uint64(attrVal[:])
|
|
info["ntlmssp.Timestamp"] = fmt.Sprintf("0x%.16x", ts)
|
|
|
|
}
|
|
|
|
// End of List
|
|
if attrType == 0 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// TrimName removes null bytes and trims leading and trailing spaces from a string
|
|
func TrimName(name string) string {
|
|
return strings.TrimSpace(strings.Replace(name, "\x00", "", -1))
|
|
}
|
|
|
|
// SMB2NegotiateProtocolRequest generates a new Negotiate request with the specified target name
|
|
func SMB2NegotiateProtocolRequest(dst string) []byte {
|
|
|
|
base := []byte{
|
|
0xfe, 0x53, 0x4d, 0x42,
|
|
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x05, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
|
|
}
|
|
|
|
// Client GUID (16)
|
|
base = append(base[:], RandomBytes(16)...)
|
|
|
|
base = append(base[:], []byte{
|
|
0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
|
0x02, 0x02, 0x10, 0x02, 0x00, 0x03, 0x02, 0x03,
|
|
0x11, 0x03, 0x00, 0x00, 0x01, 0x00, 0x26, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00,
|
|
0x01, 0x00,
|
|
}...)
|
|
|
|
// SHA-512 Salt (32)
|
|
base = append(base[:], RandomBytes(32)...)
|
|
|
|
base = append(base[:], []byte{
|
|
0x00, 0x00, 0x02, 0x00, 0x06, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
}...)
|
|
|
|
encodedDst := make([]byte, len(dst)*2)
|
|
for i, b := range []byte(dst) {
|
|
encodedDst[i*2] = b
|
|
}
|
|
|
|
netname := []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
binary.LittleEndian.PutUint16(netname[2:], uint16(len(encodedDst)))
|
|
netname = append(netname, encodedDst...)
|
|
|
|
base = append(base, netname...)
|
|
|
|
nbhd := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(nbhd, uint32(len(base)))
|
|
nbhd = append(nbhd, base...)
|
|
fmt.Println(string(nbhd))
|
|
return nbhd
|
|
}
|