package smb import ( "github.com/izouxv/logx" "imuslab.com/smb/driver/mod/smb/encoder" ) // Function属性 const ( FSCTL_DFS_GET_REFERRALS = 0x00060194 FSCTL_PIPE_PEEK = 0x0011400C FSCTL_PIPE_WAIT = 0x00110018 FSCTL_PIPE_TRANSCEIVE uint32 = 0x0011C017 FSCTL_SRV_COPYCHUNK = 0x001440F2 FSCTL_SRV_ENUMERATE_SNAPSHOTS = 0x00144064 FSCTL_SRV_REQUEST_RESUME_KEY = 0x00140078 FSCTL_SRV_READ_HASH = 0x001441bb FSCTL_SRV_COPYCHUNK_WRITE = 0x001480F2 FSCTL_LMR_REQUEST_RESILIENCY = 0x001401D4 FSCTL_QUERY_NETWORK_INTERFACE_INFO = 0x001401FC FSCTL_SET_REPARSE_POINT = 0x000900A4 FSCTL_DFS_GET_REFERRALS_EX = 0x000601B0 FSCTL_FILE_LEVEL_TRIM = 0x00098208 FSCTL_VALIDATE_NEGOTIATE_INFO = 0x00140204 ) // Flags属性 const ( SMB2_0_IOCTL_IS_IOCTL = 0x00000000 SMB2_0_IOCTL_IS_FSCTL = 0x00000001 ) func init() { commandRequestMap[CommandIOCtl] = func() DataI { return &IOCTLRequest{} } } // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5c03c9d6-15de-48a2-9835-8fb37f8a79d8 type IOCTLRequest struct { Header StructureSize uint16 Reserved uint16 Function uint32 GUIDHandle GUID //GUIDHandle []byte `smb:"fixed:16"` InputOffset uint32 `smb:"offset:Buffer"` InputLength uint32 `smb:"len:Buffer"` MaxInputSize uint32 OutputOffset uint32 OutputLength uint32 MaxOutputSize uint32 Flags uint32 Reserved2 uint32 Buffer []byte //Buffer interface{} } // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/f70eccb6-e1be-4db8-9c47-9ac86ef18dbb type IOCTLResponse struct { Header StructureSize uint16 //always 49 Reserved uint16 Function uint32 //CtlCode GUIDHandle GUID //FileId []byte `smb:"fixed:16"` BlobOffset uint32 //InputOffset BlobLength uint32 //InputCount BlobOffset2 uint32 //OutputOffset BlobLength2 uint32 //OutputCount Flags uint32 Reserved2 uint32 Buffer []byte } func (data *IOCTLRequest) ServerAction(ctx *DataCtx) (interface{}, error) { data.Header.Flags = SMB2_FLAGS_RESPONSE if data.Flags != SMB2_0_IOCTL_IS_FSCTL { return ERR(data.Header, STATUS_NOT_SUPPORTED) } if !data.GUIDHandle.IsSvrSvc(ctx.session) { return ERR(data.Header, STATUS_NOT_SUPPORTED) } var pdudata []byte /* if data.Flags == SMB2_0_IOCTL_IS_FSCTL { decoded, _ := hex.DecodeString("980000000f000000000000000000000000e1f505000000001700000000000000fe8000000000000000ebcb3570ade0f20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") pdudata = decoded log.Println(pdudata) } */ switch data.Function { case FSCTL_PIPE_WAIT: piple := FSCTLPIPEWAITRequestStruct{} if err := encoder.Unmarshal(data.Buffer, &piple); err != nil { } nameStr := string(piple.Name) logx.Debug("Unmarshalling Ioctl stdin pipe response ["+nameStr+"]", nil) case FSCTL_PIPE_TRANSCEIVE: _, err := DcerpcWrite(ctx, &WriteRequest{Data: data.Buffer}) if err != nil { return ERR(data.Header, STATUS_UNSUCCESSFUL) } pdudata, err = DcerpcReadRaw(ctx) if err != nil { return ERR(data.Header, STATUS_UNSUCCESSFUL) } } resp := IOCTLResponse{ Header: data.Header, StructureSize: 0x31, Function: data.Function, GUIDHandle: data.GUIDHandle, BlobOffset2: 0x70, BlobLength2: uint32(len(pdudata)), Buffer: pdudata, } return &resp, nil } // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/f030a3b9-539c-4c7b-a893-86b795b9b711 // 请求服务器等待连接 type FSCTLPIPEWAITRequestStruct struct { Timeout uint64 // 毫秒单位 NameLength uint32 TimeoutSpecified uint8 // 一个布尔值,指定是否忽略Timeout参数 Padding uint8 Name []byte // 命名管道名称的Unicode字符串,名称不得包含“\pipe\” } func (c *SessionC) NewFSCTLPIPEWAITRequest(pipename string) FSCTLPIPEWAITRequestStruct { pipeName := encoder.ToUnicode(pipename) return FSCTLPIPEWAITRequestStruct{ NameLength: uint32(len(pipeName)), TimeoutSpecified: 1, Padding: 0, Name: pipeName, } } /* // 连接并绑定命名管道,并拿到管道句柄 func (c *Session) ConnectAndWriteStdInPipes(pipename string) (treeid uint32, pipehandle []byte, err error) { timeout := uint64(500000) treeId, err := c.TreeConnect("IPC$") if err != nil { c.Debug("", err) return 0, nil, err } IOCTLRequest := c.NewIOCTLRequest(treeId) // 使用FSCTL_PIPE_WAIT,FileId必须为0xFFFFFFFFFFFFFFFF IOCTLRequest.Function = FSCTL_PIPE_WAIT IOCTLRequest.Flags = SMB2_0_IOCTL_IS_FSCTL IOCTLRequest.GUIDHandle = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} // 连接管道 FSCTLPIPEWAITRequestIn := c.NewFSCTLPIPEWAITRequest(pipename) FSCTLPIPEWAITRequestIn.Timeout = timeout IOCTLRequest.Buffer = FSCTLPIPEWAITRequestIn c.Debug("Sending Ioctl stdin pipe request ["+pipename+"]", nil) buf, err := c.Send(IOCTLRequest) if err != nil { c.Debug("", err) return 0, nil, err } res := NewIOCTLResponse() c.Debug("Unmarshalling Ioctl stdin pipe response ["+pipename+"]", nil) if err = encoder.Unmarshal(buf, &res); err != nil { c.Debug("Raw:\n"+hex.Dump(buf), err) return 0, nil, err } // 创建管道请求 pipeHander, err := c.CreatePipeRequest(treeId, pipename) if err != nil { return 0, nil, err } // 将数据写入管道 err = c.WritePipeRequest(treeId, []byte("cmd"), pipeHander) if err != nil { return 0, nil, err } return treeId, pipeHander, nil } // 拿到stdin、out、err句柄 func (c *Session) ConnectAndBindNamedPipes(pipename string) (stdinpipe, stdoutpipe, stderrpipe []byte, err error) { var stdIn, stdOut, stdErr []byte timeout := uint64(500000) treeId, err := c.TreeConnect("IPC$") if err != nil { c.Debug("", err) //return nil, err } IOCTLRequest := c.NewIOCTLRequest(treeId) // 使用FSCTL_PIPE_WAIT,FileId必须为0xFFFFFFFFFFFFFFFF IOCTLRequest.Function = FSCTL_PIPE_WAIT IOCTLRequest.Flags = SMB2_0_IOCTL_IS_FSCTL IOCTLRequest.GUIDHandle = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} // 连接输入管道 pipeIn := pipename + "_in" FSCTLPIPEWAITRequestIn := c.NewFSCTLPIPEWAITRequest(pipeIn) FSCTLPIPEWAITRequestIn.Timeout = timeout IOCTLRequest.Buffer = FSCTLPIPEWAITRequestIn c.Debug("Sending Ioctl stdin pipe request ["+pipeIn+"]", nil) buf, err := c.Send(IOCTLRequest) if err != nil { c.Debug("", err) //return nil, err } res := NewIOCTLResponse() c.Debug("Unmarshalling Ioctl stdin pipe response ["+pipeIn+"]", nil) if err := encoder.Unmarshal(buf, &res); err != nil { c.Debug("Raw:\n"+hex.Dump(buf), err) } stdIn = res.GUIDHandle c.Debug("Completed Ioctl stdin pipe ["+pipeIn+"]", nil) // 连接输出管道 pipeOut := pipename + "_out" FSCTLPIPEWAITRequestOut := c.NewFSCTLPIPEWAITRequest(pipeOut) FSCTLPIPEWAITRequestOut.Timeout = timeout IOCTLRequest.Buffer = FSCTLPIPEWAITRequestOut c.Debug("Sending Ioctl stdout pipe request ["+pipeOut+"]", nil) buf, err = c.Send(IOCTLRequest) if err != nil { c.Debug("", err) //return nil, err } res = NewIOCTLResponse() c.Debug("Unmarshalling Ioctl stdout pipe response ["+pipeOut+"]", nil) if err = encoder.Unmarshal(buf, &res); err != nil { c.Debug("Raw:\n"+hex.Dump(buf), err) } c.Debug("Completed Ioctl stdout pipe ["+pipeOut+"]", nil) // 创建 // 连接错误管道 pipeErr := pipename + "_err" FSCTLPIPEWAITRequestErr := c.NewFSCTLPIPEWAITRequest(pipeErr) FSCTLPIPEWAITRequestErr.Timeout = timeout IOCTLRequest.Buffer = FSCTLPIPEWAITRequestErr c.Debug("Sending Ioctl stderr pipe request ["+pipeErr+"]", nil) buf, err = c.Send(IOCTLRequest) if err != nil { c.Debug("", err) //return nil, err } res = NewIOCTLResponse() c.Debug("Unmarshalling Ioctl stderr pipe response ["+pipeErr+"]", nil) if err = encoder.Unmarshal(buf, &res); err != nil { c.Debug("Raw:\n"+hex.Dump(buf), err) } c.Debug("Completed Ioctl stderr pipe ["+pipeErr+"]", nil) return stdIn, stdOut, stdErr, nil } func NewIOCTLRequest(treeId uint32) IOCTLRequestStruct { // smb2Header := NewSMB2Header() // smb2Header.Command = smb.SMB2_IOCTL // smb2Header.CreditCharge = 1 // smb2Header.MessageId = c.GetMessageId() // smb2Header.SessionId = c.GetSessionId() // smb2Header.TreeId = treeId // smb2Header.Credits = 127 return IOCTLRequestStruct{ Header: Header{ Command: CommandIOCtl.INT(), Credits: 127, CreditCharge: 1, }, StructureSize: 57, GUIDHandle: make([]byte, 16), } } */