123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- package smb
- import (
- cryptorand "crypto/rand"
- "encoding/asn1"
- "errors"
- "fmt"
- "time"
- "imuslab.com/smb/driver/mod/gss"
- )
- const (
- // kMaxTransactSize = 0x800000
- // kMaxTransactSizeSmb1 = 4194304
- kMaxTransactSize = 1048576
- kMaxTransactSizeSmb1 = 1048576
- )
- // var gSPNEGOResponse = []byte{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,
- // 0xa3, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0x1b, 0x24, 0x6e, 0x6f, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x52, 0x46, 0x43, 0x34, 0x31, 0x37, 0x38, 0x40, 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65}
- const (
- SMB2_GLOBAL_CAP_DFS = 0x00000001
- SMB2_GLOBAL_CAP_LEASING = 0x00000002
- SMB2_GLOBAL_CAP_LARGE_MTU = 0x00000004
- SMB2_GLOBAL_CAP_MULTI_CHANNEL = 0x00000008
- SMB2_GLOBAL_CAP_PERSISTENT_HANDLES = 0x00000010
- SMB2_GLOBAL_CAP_DIRECTORY_LEASING = 0x00000020
- SMB2_GLOBAL_CAP_ENCRYPTION = 0x00000040
- )
- func timeToFiletime(tm time.Time) uint64 {
- nsec := tm.UnixNano()
- // convert into 100-nanosecond
- nsec /= 100
- // change starting time to January 1, 1601
- nsec += 116444736000000000
- return uint64(nsec)
- }
- type HeaderSmb1 struct {
- ProtocolID []byte `smb:"fixed:4"`
- SmbCommand uint8 //0x72: negotiate protocol
- NtStatus uint32
- Flags uint8 //case sensitivity
- Flags2 uint16
- PricessId uint16
- Signature []byte `smb:"fixed:8"`
- Reserved uint16
- TreeId uint16
- ProcessId uint16
- UserId uint16
- MultiplexId uint16
- }
- type NegotiateSmb1Request struct {
- HeaderSmb1
- WordCount uint8
- ByteCount uint16
- // Dialects []uint16
- }
- type NegotiateRequest struct {
- Header
- StructureSize uint16
- DialectCount uint16 `smb:"count:Dialects"`
- SecurityMode uint16
- Reserved uint16
- Capabilities uint32
- ClientGuid []byte `smb:"fixed:16"`
- ClientStartTime uint64
- Dialects []uint16
- }
- var myMech = func() asn1.ObjectIdentifier {
- myMechType := gss.NtLmSSPMechTypeOid
- // Check for NTLMSSP support
- mySSPOID, err := gss.ObjectIDStrToInt(myMechType)
- if err != nil {
- panic(-1)
- }
- return asn1.ObjectIdentifier(mySSPOID)
- }
- type NegotiateResponse struct {
- Header
- StructureSize uint16
- SecurityMode uint16
- DialectRevision uint16
- Reserved uint16
- ServerGuid []byte `smb:"fixed:16"`
- Capabilities uint32
- MaxTransactSize uint32
- MaxReadSize uint32
- MaxWriteSize uint32
- SystemTime uint64
- ServerStartTime uint64
- SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"`
- SecurityBufferLength uint16 `smb:"len:SecurityBlob"`
- Reserved2 uint32
- SecurityBlob *gss.NegTokenInit
- }
- func (data *NegotiateSmb1Request) ServerAction(ctx *DataCtx) (interface{}, error) {
- req := &NegotiateRequest{
- Dialects: []uint16{DialectSmb_2_0_2},
- }
- resp := NegotiateResponse{
- Header: newHeader(CommandNegotiate, 0, 0),
- SecurityBlob: &gss.NegTokenInit{},
- }
- resp.Header.CreditCharge = 0
- resp.Header.Credits = 1
- resp.Header.Status = StatusOk
- resp.Header.Flags = SMB2_FLAGS_RESPONSE
- resp.Header.Reserved = 1
- if true {
- //check dialect
- foundMyVer := false
- for _, d := range req.Dialects {
- if d == DialectSmb_2_1 || d == DialectSmb_2_0_2 {
- foundMyVer = true
- }
- }
- if !foundMyVer {
- return ERR(req.Header, STATUS_NOT_SUPPORTED)
- }
- }
- // ctx.session.dialect = uint16(DialectSmb_2_0_2)
- // ctx.session.dialect = uint16(DialectSmb_2_1)
- spnegoOID, err := gss.ObjectIDStrToInt(gss.SpnegoOid)
- if err != nil {
- return ERR(req.Header, STATUS_INVALID_PARAMETER)
- }
- resp.SecurityBlob.OID = asn1.ObjectIdentifier(spnegoOID)
- resp.SecurityBlob.Data.MechTypes = []asn1.ObjectIdentifier{myMech()}
- resp.SecurityMode = SecurityModeSigningEnabled //| SecurityModeSigningRequired 这个需要验证header的signature
- var gServerGuid []byte = func() []byte {
- // type GUID [16]byte
- var g GUID
- mustReadRand := func(dst []byte) {
- _, err := cryptorand.Read(dst[:])
- if err != nil {
- panic(err)
- }
- }
- mustReadRand(g[:])
- return g[:]
- }()
- resp.StructureSize = 0x41
- // resp.SecurityMode = 0x03
- resp.DialectRevision = DialectSmb2_ALL
- resp.ServerGuid = gServerGuid
- resp.Capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU
- resp.MaxTransactSize = kMaxTransactSizeSmb1
- resp.MaxReadSize = kMaxTransactSizeSmb1
- resp.MaxWriteSize = kMaxTransactSizeSmb1
- resp.SystemTime = timeToFiletime(time.Now())
- resp.SecurityBufferOffset = 0x80
- // resp.SecurityBufferLength = uint16(len(gSPNEGOResponse))
- return &resp, nil
- // return req.serverAction(ctx, resp)
- }
- func (data *NegotiateRequest) ServerAction(ctx *DataCtx) (interface{}, error) {
- resp := NegotiateResponse{
- SecurityBlob: &gss.NegTokenInit{},
- }
- resp.Header = data.Header
- resp.Header.Credits = 1
- resp.Header.Status = StatusOk
- resp.StructureSize = 65
- resp.Header.Flags = SMB2_FLAGS_RESPONSE
- if true {
- //check dialect
- foundMyVer := false
- for _, d := range data.Dialects {
- if d == DialectSmb_2_1 {
- foundMyVer = true
- }
- }
- if !foundMyVer {
- return ERR(data.Header, STATUS_NOT_SUPPORTED)
- }
- }
- fmt.Printf("clientSupportDialect: %v", data.Dialects)
- fmt.Println()
- ctx.session.dialect = uint16(DialectSmb_2_1)
- return data.serverAction(ctx, resp)
- }
- func (data *NegotiateRequest) serverAction(ctx *DataCtx, resp NegotiateResponse) (interface{}, error) {
- spnegoOID, err := gss.ObjectIDStrToInt(gss.SpnegoOid)
- if err != nil {
- return ERR(data.Header, STATUS_INVALID_PARAMETER)
- }
- resp.SecurityBlob.OID = asn1.ObjectIdentifier(spnegoOID)
- resp.SecurityBlob.Data.MechTypes = []asn1.ObjectIdentifier{myMech()}
- resp.SecurityMode = SecurityModeSigningEnabled //| SecurityModeSigningRequired 这个需要验证header的signature
- resp.DialectRevision = ctx.session.dialect
- var gServerGuid []byte = func() []byte {
- // type GUID [16]byte
- var g GUID
- mustReadRand := func(dst []byte) {
- _, err := cryptorand.Read(dst[:])
- if err != nil {
- panic(err)
- }
- }
- mustReadRand(g[:])
- return g[:]
- }()
- resp.ServerGuid = gServerGuid
- resp.Capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU //| SMB2_GLOBAL_CAP_DIRECTORY_LEASING // TODO: check 3.3.5.4, page 259
- resp.MaxTransactSize = kMaxTransactSize
- resp.MaxReadSize = kMaxTransactSize
- resp.MaxWriteSize = kMaxTransactSize
- resp.SystemTime = timeToFiletime(time.Now())
- resp.SecurityBufferOffset = 0x80
- // resp.SecurityBufferLength = uint16(len(gSPNEGOResponse))
- return &resp, nil
- }
- func (negReq *NegotiateRequest) ClientAction(s *SessionC, negRes *NegotiateResponse) error {
- myMechType := gss.NtLmSSPMechTypeOid
- if negRes.Header.Status != StatusOk {
- return errors.New(fmt.Sprintf("NT Status Error: %d\n", negRes.Header.Status))
- }
- // Check SPNEGO security blob
- spnegoOID, err := gss.ObjectIDStrToInt(gss.SpnegoOid)
- if err != nil {
- return err
- }
- oid := negRes.SecurityBlob.OID
- if !oid.Equal(asn1.ObjectIdentifier(spnegoOID)) {
- return errors.New(fmt.Sprintf(
- "Unknown security type OID [expecting %s]: %s\n",
- gss.SpnegoOid,
- negRes.SecurityBlob.OID))
- }
- // Check for NTLMSSP support
- mySSPOID, err := gss.ObjectIDStrToInt(myMechType)
- if err != nil {
- s.Debug("", err)
- return err
- }
- hasMySSP := false
- for _, mechType := range negRes.SecurityBlob.Data.MechTypes {
- if mechType.Equal(asn1.ObjectIdentifier(mySSPOID)) {
- hasMySSP = true
- break
- }
- }
- if !hasMySSP {
- return errors.New("Server does not support NTLMSSP")
- }
- s.securityMode = negRes.SecurityMode
- s.dialect = negRes.DialectRevision
- // Determine whether signing is required
- mode := uint16(s.securityMode)
- if mode&SecurityModeSigningEnabled > 0 {
- if mode&SecurityModeSigningRequired > 0 {
- s.IsSigningRequired = true
- } else {
- s.IsSigningRequired = false
- }
- } else {
- s.IsSigningRequired = false
- }
- return nil
- }
- func (s *SessionC) NewNegotiateRequest() *NegotiateRequest {
- header := s.newHeader(CommandNegotiate)
- dialects := []uint16{
- uint16(DialectSmb_2_1),
- uint16(DialectSmb_3_0),
- uint16(DialectSmb_3_0_2),
- }
- return &NegotiateRequest{
- Header: header,
- StructureSize: 36,
- DialectCount: uint16(len(dialects)),
- SecurityMode: SecurityModeSigningEnabled,
- Reserved: 0,
- Capabilities: 0,
- ClientGuid: make([]byte, 16),
- ClientStartTime: 0,
- Dialects: dialects,
- }
- }
|