GoSecure / pyrdp

RDP monster-in-the-middle (mitm) and library for Python with the ability to watch connections live or after the fact
https://www.gosecure.net/blog/2020/10/20/announcing-pyrdp-1/
GNU General Public License v3.0
1.55k stars 248 forks source link

Support for xrdp backend #294

Open khast3x opened 3 years ago

khast3x commented 3 years ago

Hello,

Does PyRDP support using the mitm feature in front of a xrdp server? If not, this could help deploy honeypots with a small alpine/ubuntu container acting as RDP backend. This is the current output when running as a mitm for a ubuntu+xrdp container (it is a bit verbose, sorry):

user@dockervps:~# docker run -d --name uxrdp --hostname terminalserver --shm-size 1g danielguerra/ubuntu-xrdp
user@dockervps:~# docker run -p 3389:3389 gosecure/pyrdp pyrdp-mitm.py 172.17.0.2
[2021-02-04 18:53:46,507] - INFO - GLOBAL - pyrdp.mitm - Target: 172.17.0.2:3389
[2021-02-04 18:53:46,507] - INFO - GLOBAL - pyrdp.mitm - Output directory: /home/pyrdp/pyrdp_output
[2021-02-04 18:53:46,509] - INFO - GLOBAL - pyrdp - MITM Server listening on port 3389
[2021-02-04 18:54:16,729] - INFO - Jeanne859549 - pyrdp.mitm.connections.tcp - New client connected from xx.xx.xx.22
[2021-02-04 18:54:16,730] - INFO - Jeanne859549 - pyrdp.mitm.connections.x224 - No cookie for this connection
[2021-02-04 18:54:16,733] - INFO - Jeanne859549 - pyrdp.mitm.connections.tcp - Server connected
[2021-02-04 18:54:17,856] - INFO - Jeanne859549 - pyrdp.mitm.connections.cert - Cloned server certificate to pyrdp_output/certs/Terminalserver.crt
CLIENT_RANDOM 605840d49e2b351091cb3c83a154c7923c09e1a634c24958c494429050124282 c0898b9270fb5aa7483ac14c8deb1fdfa3c89921419396cbf364f08b8b8f81f7ad34098bd28257bf611a8a11546a03aa
[2021-02-04 18:54:20,520] - INFO - Jeanne859549 - pyrdp.mitm.connections.mcs - Client hostname shinyboi
CLIENT_RANDOM 13e4e08473315c9113328b458a64b9ca6b380172d89e06ffdae5fad186ab2068 aab6858872e3782f775abaae75feae9e0d20854de346676dc44ffa3f7c17b2456a0350a184f03f03bbedc2cacdb1eeee
[2021-02-04 18:54:21,318] - INFO - Jeanne859549 - pyrdp.mitm.connections.security - Client Info: username = '\x00', password = '\x00', domain = '\x00', clientAddress = '192.168.1.63\x00\x00'
[2021-02-04 18:54:21,422] - ERROR - Jeanne859549 - pyrdp.mitm.connections.tcp - 6 is not a valid CapabilityType
ValueError: 6 is not a valid CapabilityType

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/tcp.py", line 92, in dataReceived
    self.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/segmentation.py", line 79, in recv
    layer.recv(forwarded)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/buffered.py", line 55, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 110, in pduReceived
    self.observer.onPDUReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/core/observer.py", line 82, in __call__
    self.composite.doCall(self.item, args, kwargs)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/core/observer.py", line 56, in doCall
    getattr(observer, item)(*args, **kwargs)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 48, in onPDUReceived
    self.handlers[pdu.header](pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/mitm/MCSMITM.py", line 257, in onSendDataIndication
    self.serverChannels[pdu.channelID].recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/mcs/channel.py", line 33, in recv
    self.next.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/rdp/security.py", line 142, in recv
    self.next.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 142, in recv
    pdu = self.mainParser.parse(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/parser.py", line 49, in parse
    return super().parse(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/parser.py", line 24, in parse
    return self.doParse(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/rdp/slowpath.py", line 67, in doParse
    return self.parsers[header.pduType](stream, header)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/rdp/slowpath.py", line 156, in parseDemandActive
    parsedCapabilitySets = self.parseCapabilitySets(capabilitySets, numberCapabilities)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/rdp/slowpath.py", line 199, in parseCapabilitySets
    capabilitySets[CapabilityType(capabilitySetType)] = capability
  File "/usr/lib/python3.8/enum.py", line 309, in __call__
    return cls.__new__(cls, value)
  File "/usr/lib/python3.8/enum.py", line 600, in __new__
    raise exc
  File "/usr/lib/python3.8/enum.py", line 584, in __new__
    result = cls._missing_(value)
  File "/usr/lib/python3.8/enum.py", line 613, in _missing_
    raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 6 is not a valid CapabilityType
[2021-02-04 18:54:21,427] - ERROR - Jeanne859549 - pyrdp.mitm.connections.tcp - Exception occurred when receiving: 030001bc02f08068000103eb7081adad011100ea03ea03010004009701524450000f00000009000800ea03b5e201001800010003000002000000000104000000000000000002001c000000010001000100000000000000010001000000000000000e000400030058000000000000000000000000000000000040420f0001001400000001002f0022000101010100000000010001000000000000000100000000000000000100000000a106020040420f0040420f0001000000000000001d005d0004b91b8dca0f004f15589fae2d1a87e2d6010300010103122f777672bd6344afb3b73c9c6f788600040000000000d4cc44278a9d744e803c0ecbeea19c5400040000000000e64caf1bed9e0c43869acb8b37b662370001004b0a0008000600000008000a000100190019000d0058003d0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000170008000300000018000b0002000000030c0006000500001a000800000030001e000800020000001c000c00520000000000000000000000

Traceback (most recent call last):
  File "/opt/venv/lib/python3.8/site-packages/twisted/python/log.py", line 103, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/opt/venv/lib/python3.8/site-packages/twisted/python/log.py", line 86, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/opt/venv/lib/python3.8/site-packages/twisted/python/context.py", line 122, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/opt/venv/lib/python3.8/site-packages/twisted/python/context.py", line 85, in callWithContext
    return func(*args,**kw)
--- <exception caught here> ---
  File "/opt/venv/lib/python3.8/site-packages/twisted/internet/asyncioreactor.py", line 136, in _readOrWrite
    why = method()
  File "/opt/venv/lib/python3.8/site-packages/twisted/internet/tcp.py", line 243, in doRead
    return self._dataReceived(data)
  File "/opt/venv/lib/python3.8/site-packages/twisted/internet/tcp.py", line 249, in _dataReceived
    rval = self.protocol.dataReceived(data)
  File "/opt/venv/lib/python3.8/site-packages/twisted/protocols/tls.py", line 330, in dataReceived
    self._flushReceiveBIO()
  File "/opt/venv/lib/python3.8/site-packages/twisted/protocols/tls.py", line 295, in _flushReceiveBIO
    ProtocolWrapper.dataReceived(self, bytes)
  File "/opt/venv/lib/python3.8/site-packages/twisted/protocols/policies.py", line 120, in dataReceived
    self.wrappedProtocol.dataReceived(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/tcp.py", line 92, in dataReceived
    self.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/segmentation.py", line 79, in recv
    layer.recv(forwarded)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/buffered.py", line 55, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 110, in pduReceived
    self.observer.onPDUReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/core/observer.py", line 82, in __call__
    self.composite.doCall(self.item, args, kwargs)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/core/observer.py", line 56, in doCall
    getattr(observer, item)(*args, **kwargs)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 48, in onPDUReceived
    self.handlers[pdu.header](pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/mitm/MCSMITM.py", line 257, in onSendDataIndication
    self.serverChannels[pdu.channelID].recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/mcs/channel.py", line 33, in recv
    self.next.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/rdp/security.py", line 142, in recv
    self.next.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 142, in recv
    pdu = self.mainParser.parse(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/parser.py", line 49, in parse
    return super().parse(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/parser.py", line 24, in parse
    return self.doParse(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/rdp/slowpath.py", line 67, in doParse
    return self.parsers[header.pduType](stream, header)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/rdp/slowpath.py", line 156, in parseDemandActive
    parsedCapabilitySets = self.parseCapabilitySets(capabilitySets, numberCapabilities)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.0.1.dev0-py3.8-linux-x86_64.egg/pyrdp/parser/rdp/slowpath.py", line 199, in parseCapabilitySets
    capabilitySets[CapabilityType(capabilitySetType)] = capability
  File "/usr/lib/python3.8/enum.py", line 309, in __call__
    return cls.__new__(cls, value)
  File "/usr/lib/python3.8/enum.py", line 600, in __new__
    raise exc
  File "/usr/lib/python3.8/enum.py", line 584, in __new__
    result = cls._missing_(value)
  File "/usr/lib/python3.8/enum.py", line 613, in _missing_
    raise ValueError("%r is not a valid %s" % (value, cls.__name__))
builtins.ValueError: 6 is not a valid CapabilityType

[2021-02-04 18:54:21,431] - INFO - Jeanne859549 - pyrdp.mitm.connections.tcp - Server connection closed. Connection to the other side was lost in a non-clean fashion: Connection lost.

Cheers!

michelbf commented 3 years ago

This would be really helpful as I'm also looking to using this in an Ubuntu honeypot running xrdp.

jkasser commented 3 years ago

Hey @michelbf @khast3x, have either of you figured out a way around this? I am running into it as well.

michelbf commented 3 years ago

I, unfortunately, don't have a solution for this.

khast3x commented 3 years ago

Same ^

dylanhudson commented 3 years ago

Also wrestling with this error; can't say I have a solution but maybe someone who knows more about xRDP can shed some light on what I've found so far:

On page 91 of Microsoft's RDP spec, they lay out the structure for CapabilitySets. As you can see, there is no corresponding type for a value of 6. The structure is mirrored in PyRDP here - https://github.com/GoSecure/pyrdp/blob/933ca2aac09f0b993c5937eb346c61c2052c4d94/pyrdp/enum/rdp.py#L409

It appears from the above stack trace that xRDP has sent a CapabilitySetType of 6, which does not exist. I'm trying to track down where and why this is set in the xRDP source- my best guess so far is here on line 87- https://github.com/neutrinolabs/xrdp/blob/devel/libxrdp/xrdp_caps.c ...but I don't know squat about xRDP. If I have time to read and understand more of the code that sets the CapabilitySetType, I'll make some changes and try building from source, and see what happens, or if there's any further useful errors.

obilodeau commented 3 years ago

You could just add an entry in the enum in pyrdp and test. Something like:

    CAPSTYPE_BOGUS_XRDP = 0x0006

and see if everything starts working from there or if something fails

jkasser commented 3 years ago

I made that change and am now digging into this error:

[2021-10-15 18:46:51,772] - ERROR - Ted978785 - pyrdp.mitm.connections.tcp - <CapabilityType.CAPSTYPE_VIRTUALCHANNEL: 20>
Traceback (most recent call last):
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/tcp.py", line 92, in dataReceived
    self.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/segmentation.py", line 79, in recv
    layer.recv(forwarded)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/buffered.py", line 55, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 203, in pduReceived
    self.next.recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 110, in pduReceived
    self.observer.onPDUReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/core/observer.py", line 82, in __call__
    self.composite.doCall(self.item, args, kwargs)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/core/observer.py", line 56, in doCall
    getattr(observer, item)(*args, **kwargs)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 48, in onPDUReceived
    self.handlers[pdu.header](pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/mitm/MCSMITM.py", line 259, in onSendDataIndication
    self.serverChannels[pdu.channelID].recv(pdu.payload)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/mcs/channel.py", line 33, in recv
    self.next.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/rdp/security.py", line 142, in recv
    self.next.recv(data)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 145, in recv
    self.pduReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/layer.py", line 110, in pduReceived
    self.observer.onPDUReceived(pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/core/observer.py", line 82, in __call__
    self.composite.doCall(self.item, args, kwargs)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/core/observer.py", line 56, in doCall
    getattr(observer, item)(*args, **kwargs)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/mitm/SlowPathMITM.py", line 56, in onServerPDUReceived
    SlowPathObserver.onPDUReceived(self.serverObserver, pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/layer/rdp/slowpath.py", line 49, in onPDUReceived
    self.handlers[pdu.header.pduType](pdu)
  File "/opt/venv/lib/python3.8/site-packages/pyrdp-1.1.1.dev0-py3.8-linux-x86_64.egg/pyrdp/mitm/SlowPathMITM.py", line 112, in onDemandActive
    pdu.parsedCapabilitySets[CapabilityType.CAPSTYPE_VIRTUALCHANNEL].flags = \
KeyError: <CapabilityType.CAPSTYPE_VIRTUALCHANNEL: 20>
obilodeau commented 3 years ago

I don't understand why but there is no VirtualChannel setup at this point in the connection yet PyRDP assumes there is. Apply this patch. It will test if there's a virtualchannel before trying to disable its compression.

diff --git a/pyrdp/mitm/SlowPathMITM.py b/pyrdp/mitm/SlowPathMITM.py
index 0bff4aa..f4e1dd5 100644
--- a/pyrdp/mitm/SlowPathMITM.py
+++ b/pyrdp/mitm/SlowPathMITM.py
@@ -109,5 +109,6 @@ class SlowPathMITM(BasePathMITM):
             supported[Order.TS_NEG_DRAWNINEGRID_INDEX] = 0
             orders.orderSupport = supported

-        pdu.parsedCapabilitySets[CapabilityType.CAPSTYPE_VIRTUALCHANNEL].flags = \
-            VirtualChannelCompressionFlag.VCCAPS_NO_COMPR
+        if CapabilityType.CAPSTYPE_VIRTUALCHANNEL in pdu.parsedCapabilitySets:
+            pdu.parsedCapabilitySets[CapabilityType.CAPSTYPE_VIRTUALCHANNEL].flags = \
+                VirtualChannelCompressionFlag.VCCAPS_NO_COMPR
obilodeau commented 3 years ago

Did the patch get you further? Should I add this to PyRDP?

dylanhudson commented 3 years ago

hey, sorry for not following up sooner, that was very helpful! Yes, the patch worked to resolve that, although we ran into some separate issues with our virtualization that prevented us from confirming full functionality afterwards. I think adding the patch would be great; it would be really helpful to be able to deploy it in docker without having to manually overwrite the source.

obilodeau commented 3 years ago

Added the patch to master. It will be part of the next release. Leaving this issue open since we are not sure about resolution.

saluto commented 1 year ago

In addition to the two already mentioned patches (this and this, where currently only the latter is merged/released), I also had to change 0x2a to len(pdu.payload) + 14) in parser/gcc.py#L132. It seems that XRDP would otherwise ignore the requested channels and return 0 channels, resulting in an error on the client side.

After the changes, a simple pyrdp MITM seems to work (on Linux with XRDP server and Remmina client or FreeRDP client), even though the client shows the following messages (which don't occur when connecting directly to XRDP instead of MITM server):

[...] [ERROR][com.freerdp.core.rdp] - incorrect PDU type: 0x0000
[...] [WARN][com.freerdp.core.rdp] - pduType UNKNOWN 0000 not properly parsed, 122 bytes remaining unhandled. Skipping.

I'm not sure what this might break. Also, I'm not sure whether my patch breaks support for other servers, e.g. on Windows. Could someone check that? I currently only have Linux with XRDP.