Projects STRLCPY aardwolf Commits 82d6797c
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■
    aardwolf/_version.py
    1 1   
    2  -__version__ = "0.2.2"
     2 +__version__ = "0.2.3"
    3 3  __banner__ = \
    4 4  """
    5 5  # aardwolf %s
    skipped 2 lines
  • ■ ■ ■ ■ ■
    aardwolf/commons/iosettings.py
    skipped 53 lines
    54 54   # but the client's clipboard will not be updated
    55 55   self.clipboard_use_pyperclip = True
    56 56   
     57 + # store all incloing clipboard data recieved from server. Text only
     58 + # set it to true to have a file created, or to a string with a file path
     59 + #
     60 + self.clipboard_store_data = None
     61 + 
    57 62   # determines how often the client polls for desktop changes
    58 63   self.vnc_fps = 10
    59 64   
    skipped 6 lines
  • ■ ■ ■ ■ ■ ■
    aardwolf/extensions/RDPECLIP/channel.py
    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
Please wait...
Page is in error, reload to recover