-
Notifications
You must be signed in to change notification settings - Fork 248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added credential logger #106
Conversation
@xshill Been a while since I dove into the code, but wasnt there a way to avoid having a singleton for this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allow me to suggest a rework. If I understand this correctly, there's 3 parts to this:
- Collect fast-path input while the user is on the login screen
- Collect slow-path input while the user is on the login screen
- Expect an RDPDR logged in message to know when the user logs in
Instead of forcing this whole feature into a single class, it should be split between the MITM handlers of the protocols that are relevant to it. Every protocol should have its own simple handling logic, and the collective action of all these handling functions is what makes the actual feature work.
Put fast-path input collection in FastPathMITM, slow-path input collection in SlowPathMITM, and login PDU handler in DeviceRedirectionMITM. FastPathMITM and SlowPathMITM will build up a shared input buffer if the user isn't logged in. DeviceRedirectionMITM will handle PAKID_CORE_USER_LOGGEDON
messages: set a shared loggedIn
boolean to True and log the current input buffer.
There's already an RDPMITMState class that contains data shared between all the handlers for a single connection. You can just add an input buffer, a loggedIn boolean, and all the information that should be shared between 2 or more protocol handlers in there. If the protocol handlers don't already have that state object passed in their constructors, you can just add that parameter.
If you want to extract shared logic between the fast-path and slow-path handlers, you can create a base class for both FastPathMITM and SlowPathMITM and put that logic in there. You can also just use a function that will take a buffer and a scan code and return the resulting buffer.
With the current implementation, you're:
- Using a singleton, which will most likely break when you get simultaneous connections
- Putting MITM logic in the logging module (the logging classes should be primarily simple and self-contained classes that can be tacked on to layers without many side-effects)
Thanks a lot for the feedback! I lacked the vision to clearly see how to correctly integrate this feature in the project, but your proposal makes a lot of sense. |
I refactored the feature according to your feedback. It's much cleaner, and we even have a good base to time payloads when user logs in (as requested in #98). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beside my minor comment, lgtm.
@xshill
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my perspective only minor changes required. Log formats and store some special keys in creds candidate buffer.
pyrdp/mitm/FastPathMITM.py
Outdated
self.client.sendPDU(pdu) | ||
|
||
def onScanCode(self, scanCode: int, isReleased: bool, isExtended: bool): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably store some of the special characters and output them in the logs/json. For example: backspace and tab.
A user has more chances of understanding P<\b>Passw0rd!
rather than PPassw0rd!
. I'm not too opinionated about what format it should be but since we are already seeing \x00
in some fields, we could just pass it like that, so backspace would be \x08
and tab \x09
. That's just a suggestion, something fancier would be ok too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is an example candidate currently. I tokenized each action the same way to simplify logging / parsing accuracy.
MonPass<ctrl-a><\b>Passw0rd!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems good, but for it to be fully functional you'd need to catch slow-path input as well.
For reference: slow-path inputs are less used because most clients use fast-path by default for user input, but it happens that they use slow-path only. |
Eh, sorry, I overlooked that part of your first review, I wasn't aware inputs could go through the slow-path. I added that part, and made a base class for both FastPathMITM and SlowPathMITM. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems good!
Here is the password harvester showcased in this issue #103.
I implemented a new logger based on the FastPathLogger. The new CredentialLogger is a singleton, since it needs to be referenced from somewhere it won't be defined in order to print credentials. I tried an implementation with a static method and a few static variable at first, but this once made more sense since there will never be two instances of a logger.
We keylog everything the users sends, and we save them as a candidate whenever the user presses the "ENTER" key. When we receive a confirmation that the user logged in, we print the candidate (or the buffer if the user submitted the form with a click)
When the user logs in, the logger deactivate itself. Whenever a new client connects, it gets reactivated.
This should give us good credentials most of the time, but It may give false-positives if the user press keys while not in an input field, or if he spams his keyboard right after being logged in but before receiving the "RDPDR" signal.