skipped 1 lines 2 2 import asyncio 3 3 import traceback 4 4 import enum 5 + import datetime 5 6 6 7 from aardwolf import logger 7 8 from aardwolf.channels import Channel skipped 16 lines 24 25 name = 'cliprdr' 25 26 def __init__(self, iosettings): 26 27 Channel.__init__(self, self.name, ChannelOption.INITIALIZED|ChannelOption.ENCRYPT_RDP|ChannelOption.COMPRESS_RDP|ChannelOption.SHOW_PROTOCOL) 28 + self.iosettings = iosettings 27 29 self.use_pyperclip = iosettings.clipboard_use_pyperclip 28 30 self.status = CLIPBRDSTATUS.WAITING_SERVER_INIT 29 31 self.compression_needed = False #TODO: tie it to flags skipped 1 lines 31 33 self.server_caps = None 32 34 self.server_general_caps = None 33 35 self.client_general_caps_flags = CB_GENERAL_FALGS.HUGE_FILE_SUPPORT_ENABLED | CB_GENERAL_FALGS.FILECLIP_NO_FILE_PATHS | CB_GENERAL_FALGS.STREAM_FILECLIP_ENABLED #| CB_GENERAL_FALGS.USE_LONG_FORMAT_NAMES # CB_GENERAL_FALGS.CAN_LOCK_CLIPDATA | #| CB_GENERAL_FALGS.USE_LONG_FORMAT_NAMES 34 - self.__buffer = b'' 35 36 self.current_server_formats = {} 36 37 self.__requested_format = None 37 38 self.__current_clipboard_data:RDP_CLIPBOARD_DATA_TXT = None 39 + self.__channel_fragment_buffer = b'' 38 40 39 41 async def start(self): 40 42 try: skipped 52 lines 93 95 except Exception as e: 94 96 return None, e 95 97 96 - async def __process_in(self): 98 + async def __process_in(self, hdr : CLIPRDR_HEADER , payload : bytes ): 97 99 try: 98 - hdr = CLIPRDR_HEADER.from_bytes(self.__buffer) 100 + # hdr = CLIPRDR_HEADER.from_bytes(self.__buffer) 99 101 100 102 if self.status == CLIPBRDSTATUS.RUNNING: 103 + #print(hdr.msgType) 101 104 if hdr.msgType == CB_TYPE.CB_FORMAT_LIST: 102 - fmtl = CLIPRDR_FORMAT_LIST.from_bytes(self . __buffer [8 :8 + hdr.dataLen], longnames=CB_GENERAL_FALGS.USE_LONG_FORMAT_NAMES in self.client_general_caps_flags, encoding='ascii' if CB_FLAG.CB_ASCII_NAMES in hdr.msgFlags else 'utf-16-le') 105 + fmtl = CLIPRDR_FORMAT_LIST.from_bytes(payload [:hdr.dataLen], longnames=CB_GENERAL_FALGS.USE_LONG_FORMAT_NAMES in self.client_general_caps_flags, encoding='ascii' if CB_FLAG.CB_ASCII_NAMES in hdr.msgFlags else 'utf-16-le') 106 + 103 107 self.current_server_formats = {} 104 108 for fmte in fmtl.templist: 105 109 self.current_server_formats[fmte.formatId] = fmte skipped 21 lines 127 131 logger.debug('Server rejected our copy request!') 128 132 else: 129 133 try: 130 - fmtdata = CLIPRDR_FORMAT_DATA_RESPONSE.from_bytes(self . __buffer [8 :8 + hdr.dataLen],otype=self.__requested_format) 134 + fmtdata = CLIPRDR_FORMAT_DATA_RESPONSE.from_bytes(payload [:hdr.dataLen],otype=self.__requested_format) 131 135 132 136 if self.use_pyperclip is True and self.__requested_format in [CLIPBRD_FORMAT.CF_TEXT, CLIPBRD_FORMAT.CF_UNICODETEXT]: 133 137 import pyperclip 138 + #print(fmtdata.dataobj) 134 139 pyperclip.copy(fmtdata.dataobj) 135 140 141 + if self.iosettings.clipboard_store_data is True or isinstance(self.iosettings.clipboard_store_data, str) is True: 142 + fname = self.iosettings.clipboard_store_data 143 + if self.iosettings.clipboard_store_data is True or len(fname) == 0: 144 + fname = 'clipboard_%s.txt' % (datetime.datetime.utcnow().strftime("%Y_%m_%d_%H%MZ")) 145 + with open(fname, 'a+') as f: 146 + f.write(str(fmtdata.dataobj)) 147 + 136 148 msg = RDP_CLIPBOARD_DATA_TXT() 137 149 msg.data = fmtdata.dataobj 138 150 msg.datatype = self.__requested_format skipped 6 lines 145 157 146 158 elif hdr.msgType == CB_TYPE.CB_FORMAT_DATA_REQUEST: 147 159 148 - fmtr = CLIPRDR_FORMAT_DATA_REQUEST.from_bytes(self . __buffer [8 :8 + hdr.dataLen]) 160 + fmtr = CLIPRDR_FORMAT_DATA_REQUEST.from_bytes(payload [:hdr.dataLen]) 149 161 if fmtr.requestedFormatId == self.__current_clipboard_data.datatype: 150 162 resp = CLIPRDR_FORMAT_DATA_RESPONSE() 151 163 resp.dataobj = self.__current_clipboard_data.data 152 164 resp = resp.to_bytes(self.__current_clipboard_data.datatype) 165 + 153 166 154 167 msg = CLIPRDR_HEADER.serialize_packet(CB_TYPE.CB_FORMAT_DATA_RESPONSE, CB_FLAG.CB_RESPONSE_OK, resp) 168 + #print('setting clipboard text! %s' % repr(msg)) 155 169 await self.fragment_and_send(msg) 156 170 157 171 else: skipped 3 lines 161 175 elif self.status == CLIPBRDSTATUS.WAITING_SERVER_INIT: 162 176 # we expect either CLIPRDR_CAPS or CLIPRDR_MONITOR_READY 163 177 if hdr.msgType == CB_TYPE.CB_CLIP_CAPS: 164 - self.server_caps = CLIPRDR_CAPS.from_bytes(self . __buffer [8 :8 + hdr.dataLen]) 178 + self.server_caps = CLIPRDR_CAPS.from_bytes(payload [:hdr.dataLen]) 165 179 self.server_general_caps = self.server_caps.capabilitySets[0] #it's always the generalflags 166 180 logger.debug(self.server_general_caps) 167 181 elif hdr.msgType == CB_TYPE.CB_MONITOR_READY: skipped 23 lines 191 205 192 206 193 207 194 - self.__buffer = self.__buffer[8+hdr.dataLen:] 208 + # self.__buffer = self.__buffer[8+hdr.dataLen:] 195 209 return True, None 196 210 except Exception as e: 197 211 return None, e 198 212 199 213 async def process_channel_data(self, data): 200 214 channeldata = CHANNEL_PDU_HEADER.from_bytes(data) 201 - #print('channeldata %s' % channeldata) 202 - self.__buffer += channeldata.data 215 + data = data[8:] #discarding the lower layer headers 216 + if CHANNEL_FLAG.CHANNEL_FLAG_FIRST in channeldata.flags: 217 + self.__channel_fragment_buffer = b'' 218 + 219 + self.__channel_fragment_buffer += data 203 220 if CHANNEL_FLAG.CHANNEL_FLAG_LAST in channeldata.flags: 204 - _, err = await self.__process_in() 221 + hdr = CLIPRDR_HEADER.from_bytes(self.__channel_fragment_buffer) 222 + _, err = await self.__process_in(hdr, self.__channel_fragment_buffer[8:]) 205 223 if err is not None: 206 224 raise err 207 225 208 226 async def fragment_and_send(self, data): 209 227 try: 210 - if len(data) < 16000: 211 - if self.compression_needed is False: 212 - flags = CHANNEL_FLAG.CHANNEL_FLAG_FIRST|CHANNEL_FLAG.CHANNEL_FLAG_LAST|CHANNEL_FLAG.CHANNEL_FLAG_SHOW_PROTOCOL 213 - packet = CHANNEL_PDU_HEADER.serialize_packet(flags, data) 228 + if self.compression_needed is True: 229 + raise NotImplementedError('Compression not implemented!') 230 + i = 0 231 + while(i <= len(data)): 232 + flags = CHANNEL_FLAG.CHANNEL_FLAG_SHOW_PROTOCOL 233 + chunk = data[i:i+1400] 234 + if i == 0: 235 + flags |= CHANNEL_FLAG.CHANNEL_FLAG_FIRST 236 + # the first fragment must contain the length of the total data we want to send 237 + length = len(data) 214 238 else: 215 - raise NotImplementedError('Compression not implemented!') 216 - else: 217 - raise NotImplementedError('Chunked send not implemented!') 239 + # if it's not the first fragment then the length equals to the chunk's length 240 + length = None 241 + 242 + i+= 1400 243 + if i >= len(data): 244 + flags |= CHANNEL_FLAG.CHANNEL_FLAG_LAST 245 + packet = CHANNEL_PDU_HEADER.serialize_packet(flags, chunk, length = length) 218 246 219 - sec_hdr = None 220 - if self.connection.cryptolayer is not None: 221 - sec_hdr = TS_SECURITY_HEADER() 222 - sec_hdr.flags = SEC_HDR_FLAG.ENCRYPT 223 - sec_hdr.flagsHi = 0 247 + sec_hdr = None 248 + if self.connection.cryptolayer is not None: 249 + sec_hdr = TS_SECURITY_HEADER() 250 + sec_hdr.flags = SEC_HDR_FLAG.ENCRYPT 251 + sec_hdr.flagsHi = 0 224 252 225 - await self.send_channel_data(packet, sec_hdr, None, None, False) 253 + await self.send_channel_data(packet, sec_hdr, None, None, False) 226 254 227 255 return True, False 228 256 except Exception as e: skipped 2 lines 231 259 232 260 233 261 async def process_user_data(self, data): 234 - #print('monitor out! %s' % data) 262 + #print('clipboard out! %s' % data) 235 263 if data.type == RDPDATATYPE.CLIPBOARD_DATA_TXT: 236 264 # data in, informing the server that our clipboard has changed 237 265 if data == self.__current_clipboard_data: skipped 18 lines