msg_basic_negotiate.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. package smb
  2. import (
  3. cryptorand "crypto/rand"
  4. "encoding/asn1"
  5. "errors"
  6. "fmt"
  7. "time"
  8. "imuslab.com/smb/driver/mod/gss"
  9. )
  10. const (
  11. // kMaxTransactSize = 0x800000
  12. // kMaxTransactSizeSmb1 = 4194304
  13. kMaxTransactSize = 1048576
  14. kMaxTransactSizeSmb1 = 1048576
  15. )
  16. // var gSPNEGOResponse = []byte{0x60, 0x48, 0x06, 0x06,
  17. // 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x3e, 0x30, 0x3c, 0xa0, 0x0e, 0x30, 0x0c, 0x06, 0x0a,
  18. // 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a,
  19. // 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}
  20. const (
  21. SMB2_GLOBAL_CAP_DFS = 0x00000001
  22. SMB2_GLOBAL_CAP_LEASING = 0x00000002
  23. SMB2_GLOBAL_CAP_LARGE_MTU = 0x00000004
  24. SMB2_GLOBAL_CAP_MULTI_CHANNEL = 0x00000008
  25. SMB2_GLOBAL_CAP_PERSISTENT_HANDLES = 0x00000010
  26. SMB2_GLOBAL_CAP_DIRECTORY_LEASING = 0x00000020
  27. SMB2_GLOBAL_CAP_ENCRYPTION = 0x00000040
  28. )
  29. func timeToFiletime(tm time.Time) uint64 {
  30. nsec := tm.UnixNano()
  31. // convert into 100-nanosecond
  32. nsec /= 100
  33. // change starting time to January 1, 1601
  34. nsec += 116444736000000000
  35. return uint64(nsec)
  36. }
  37. type HeaderSmb1 struct {
  38. ProtocolID []byte `smb:"fixed:4"`
  39. SmbCommand uint8 //0x72: negotiate protocol
  40. NtStatus uint32
  41. Flags uint8 //case sensitivity
  42. Flags2 uint16
  43. PricessId uint16
  44. Signature []byte `smb:"fixed:8"`
  45. Reserved uint16
  46. TreeId uint16
  47. ProcessId uint16
  48. UserId uint16
  49. MultiplexId uint16
  50. }
  51. type NegotiateSmb1Request struct {
  52. HeaderSmb1
  53. WordCount uint8
  54. ByteCount uint16
  55. // Dialects []uint16
  56. }
  57. type NegotiateRequest struct {
  58. Header
  59. StructureSize uint16
  60. DialectCount uint16 `smb:"count:Dialects"`
  61. SecurityMode uint16
  62. Reserved uint16
  63. Capabilities uint32
  64. ClientGuid []byte `smb:"fixed:16"`
  65. ClientStartTime uint64
  66. Dialects []uint16
  67. }
  68. var myMech = func() asn1.ObjectIdentifier {
  69. myMechType := gss.NtLmSSPMechTypeOid
  70. // Check for NTLMSSP support
  71. mySSPOID, err := gss.ObjectIDStrToInt(myMechType)
  72. if err != nil {
  73. panic(-1)
  74. }
  75. return asn1.ObjectIdentifier(mySSPOID)
  76. }
  77. type NegotiateResponse struct {
  78. Header
  79. StructureSize uint16
  80. SecurityMode uint16
  81. DialectRevision uint16
  82. Reserved uint16
  83. ServerGuid []byte `smb:"fixed:16"`
  84. Capabilities uint32
  85. MaxTransactSize uint32
  86. MaxReadSize uint32
  87. MaxWriteSize uint32
  88. SystemTime uint64
  89. ServerStartTime uint64
  90. SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"`
  91. SecurityBufferLength uint16 `smb:"len:SecurityBlob"`
  92. Reserved2 uint32
  93. SecurityBlob *gss.NegTokenInit
  94. }
  95. func (data *NegotiateSmb1Request) ServerAction(ctx *DataCtx) (interface{}, error) {
  96. req := &NegotiateRequest{
  97. Dialects: []uint16{DialectSmb_2_0_2},
  98. }
  99. resp := NegotiateResponse{
  100. Header: newHeader(CommandNegotiate, 0, 0),
  101. SecurityBlob: &gss.NegTokenInit{},
  102. }
  103. resp.Header.CreditCharge = 0
  104. resp.Header.Credits = 1
  105. resp.Header.Status = StatusOk
  106. resp.Header.Flags = SMB2_FLAGS_RESPONSE
  107. resp.Header.Reserved = 1
  108. if true {
  109. //check dialect
  110. foundMyVer := false
  111. for _, d := range req.Dialects {
  112. if d == DialectSmb_2_1 || d == DialectSmb_2_0_2 {
  113. foundMyVer = true
  114. }
  115. }
  116. if !foundMyVer {
  117. return ERR(req.Header, STATUS_NOT_SUPPORTED)
  118. }
  119. }
  120. // ctx.session.dialect = uint16(DialectSmb_2_0_2)
  121. // ctx.session.dialect = uint16(DialectSmb_2_1)
  122. spnegoOID, err := gss.ObjectIDStrToInt(gss.SpnegoOid)
  123. if err != nil {
  124. return ERR(req.Header, STATUS_INVALID_PARAMETER)
  125. }
  126. resp.SecurityBlob.OID = asn1.ObjectIdentifier(spnegoOID)
  127. resp.SecurityBlob.Data.MechTypes = []asn1.ObjectIdentifier{myMech()}
  128. resp.SecurityMode = SecurityModeSigningEnabled //| SecurityModeSigningRequired 这个需要验证header的signature
  129. var gServerGuid []byte = func() []byte {
  130. // type GUID [16]byte
  131. var g GUID
  132. mustReadRand := func(dst []byte) {
  133. _, err := cryptorand.Read(dst[:])
  134. if err != nil {
  135. panic(err)
  136. }
  137. }
  138. mustReadRand(g[:])
  139. return g[:]
  140. }()
  141. resp.StructureSize = 0x41
  142. // resp.SecurityMode = 0x03
  143. resp.DialectRevision = DialectSmb2_ALL
  144. resp.ServerGuid = gServerGuid
  145. resp.Capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU
  146. resp.MaxTransactSize = kMaxTransactSizeSmb1
  147. resp.MaxReadSize = kMaxTransactSizeSmb1
  148. resp.MaxWriteSize = kMaxTransactSizeSmb1
  149. resp.SystemTime = timeToFiletime(time.Now())
  150. resp.SecurityBufferOffset = 0x80
  151. // resp.SecurityBufferLength = uint16(len(gSPNEGOResponse))
  152. return &resp, nil
  153. // return req.serverAction(ctx, resp)
  154. }
  155. func (data *NegotiateRequest) ServerAction(ctx *DataCtx) (interface{}, error) {
  156. resp := NegotiateResponse{
  157. SecurityBlob: &gss.NegTokenInit{},
  158. }
  159. resp.Header = data.Header
  160. resp.Header.Credits = 1
  161. resp.Header.Status = StatusOk
  162. resp.StructureSize = 65
  163. resp.Header.Flags = SMB2_FLAGS_RESPONSE
  164. if true {
  165. //check dialect
  166. foundMyVer := false
  167. for _, d := range data.Dialects {
  168. if d == DialectSmb_2_1 {
  169. foundMyVer = true
  170. }
  171. }
  172. if !foundMyVer {
  173. return ERR(data.Header, STATUS_NOT_SUPPORTED)
  174. }
  175. }
  176. fmt.Printf("clientSupportDialect: %v", data.Dialects)
  177. fmt.Println()
  178. ctx.session.dialect = uint16(DialectSmb_2_1)
  179. return data.serverAction(ctx, resp)
  180. }
  181. func (data *NegotiateRequest) serverAction(ctx *DataCtx, resp NegotiateResponse) (interface{}, error) {
  182. spnegoOID, err := gss.ObjectIDStrToInt(gss.SpnegoOid)
  183. if err != nil {
  184. return ERR(data.Header, STATUS_INVALID_PARAMETER)
  185. }
  186. resp.SecurityBlob.OID = asn1.ObjectIdentifier(spnegoOID)
  187. resp.SecurityBlob.Data.MechTypes = []asn1.ObjectIdentifier{myMech()}
  188. resp.SecurityMode = SecurityModeSigningEnabled //| SecurityModeSigningRequired 这个需要验证header的signature
  189. resp.DialectRevision = ctx.session.dialect
  190. var gServerGuid []byte = func() []byte {
  191. // type GUID [16]byte
  192. var g GUID
  193. mustReadRand := func(dst []byte) {
  194. _, err := cryptorand.Read(dst[:])
  195. if err != nil {
  196. panic(err)
  197. }
  198. }
  199. mustReadRand(g[:])
  200. return g[:]
  201. }()
  202. resp.ServerGuid = gServerGuid
  203. 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
  204. resp.MaxTransactSize = kMaxTransactSize
  205. resp.MaxReadSize = kMaxTransactSize
  206. resp.MaxWriteSize = kMaxTransactSize
  207. resp.SystemTime = timeToFiletime(time.Now())
  208. resp.SecurityBufferOffset = 0x80
  209. // resp.SecurityBufferLength = uint16(len(gSPNEGOResponse))
  210. return &resp, nil
  211. }
  212. func (negReq *NegotiateRequest) ClientAction(s *SessionC, negRes *NegotiateResponse) error {
  213. myMechType := gss.NtLmSSPMechTypeOid
  214. if negRes.Header.Status != StatusOk {
  215. return errors.New(fmt.Sprintf("NT Status Error: %d\n", negRes.Header.Status))
  216. }
  217. // Check SPNEGO security blob
  218. spnegoOID, err := gss.ObjectIDStrToInt(gss.SpnegoOid)
  219. if err != nil {
  220. return err
  221. }
  222. oid := negRes.SecurityBlob.OID
  223. if !oid.Equal(asn1.ObjectIdentifier(spnegoOID)) {
  224. return errors.New(fmt.Sprintf(
  225. "Unknown security type OID [expecting %s]: %s\n",
  226. gss.SpnegoOid,
  227. negRes.SecurityBlob.OID))
  228. }
  229. // Check for NTLMSSP support
  230. mySSPOID, err := gss.ObjectIDStrToInt(myMechType)
  231. if err != nil {
  232. s.Debug("", err)
  233. return err
  234. }
  235. hasMySSP := false
  236. for _, mechType := range negRes.SecurityBlob.Data.MechTypes {
  237. if mechType.Equal(asn1.ObjectIdentifier(mySSPOID)) {
  238. hasMySSP = true
  239. break
  240. }
  241. }
  242. if !hasMySSP {
  243. return errors.New("Server does not support NTLMSSP")
  244. }
  245. s.securityMode = negRes.SecurityMode
  246. s.dialect = negRes.DialectRevision
  247. // Determine whether signing is required
  248. mode := uint16(s.securityMode)
  249. if mode&SecurityModeSigningEnabled > 0 {
  250. if mode&SecurityModeSigningRequired > 0 {
  251. s.IsSigningRequired = true
  252. } else {
  253. s.IsSigningRequired = false
  254. }
  255. } else {
  256. s.IsSigningRequired = false
  257. }
  258. return nil
  259. }
  260. func (s *SessionC) NewNegotiateRequest() *NegotiateRequest {
  261. header := s.newHeader(CommandNegotiate)
  262. dialects := []uint16{
  263. uint16(DialectSmb_2_1),
  264. uint16(DialectSmb_3_0),
  265. uint16(DialectSmb_3_0_2),
  266. }
  267. return &NegotiateRequest{
  268. Header: header,
  269. StructureSize: 36,
  270. DialectCount: uint16(len(dialects)),
  271. SecurityMode: SecurityModeSigningEnabled,
  272. Reserved: 0,
  273. Capabilities: 0,
  274. ClientGuid: make([]byte, 16),
  275. ClientStartTime: 0,
  276. Dialects: dialects,
  277. }
  278. }