Today I dug out an old PIX 501 from the store room to do some testing (don't ask). As expected, it already had a config including some unknown enable password so I was forced to perform a password recovery on it. I've done a million of these on routers and switches but probably only once or twice on a PIX so I wound up on Cisco's how to password recover a PIX page giving myself a quick refresher on how to do it.
The password recovery process on a PIX is version dependent, requiring the right recovery image for the installed PIX software. Fortunately for me the console was not set with a password so I could use "show ver" what was running on the box:
VPN-TEST> show ver
Cisco PIX Firewall Version 6.3(5)
Cisco PIX Device Manager Version 3.0(4)
Compiled on Thu 04-Aug-05 21:40 by morlee
<snip>
"Great", I thought, and downloaded the 6.3 recovery image. The process itself is pretty straightforward and explained on the Cisco instruction page so I won't go over it in detail. After breaking the boot sequence and firing up the TFTP I was greeted with this:
monitor> tftp
tftp 8529-np63.bin@10.10.10.1.....................................................................................................................................................................................
Received 92160 bytes
Cisco Secure PIX Firewall password tool (3.0) #0: Thu Jul 17 08:01:09 PDT 2003
Flash=E28F640J3 @ 0x3000000
BIOS Flash=E28F640J3 @ 0xD8000
Do you wish to erase the passwords? [yn]
Of course I pressed "y", only to be told:
▒o passwords or aaa commands were found.
Rebooting....
How rude! Following that I returned to trying the default cisco / pix / blank passwords, in case I'd fat-fingered them earlier, but nothing worked. There *was* a password there, dammit!
After a fair bit of searching I soon realised that this was not a common problem. There were only a couple of forum posts quoting the "no passwords or aaa commands were found" message and none of them had a solution.
Out of desperation, as much as anything, I tried the PIX 7/8 recovery image:
monitor> tftp
tftp 8529-np70.bin@10.10.10.1.............................................................................................................................................................................................................................................................
Received 129024 bytes
Cisco PIX Security Appliance password tool (3.0) #0: Thu Jun 9 21:45:44 PDT 2005
This utility is not supported on this platform
Rebooting....
Huff. OK, last try. Let's go with the next version down - 6.2 and see if that works:
monitor> tftp
tftp 8529-np62.bin@10.10.10.1.................................................................................................................................................
Received 73728 bytes
Cisco Secure PIX Firewall password tool (3.0) #0: Wed Mar 27 11:02:16 PST 2002
Flash=E28F640J3 @ 0x3000000
BIOS Flash=E28F640J3 @ 0xD8000
Do you wish to erase the passwords? [yn]
Well, at least it ran this time. Naturally I typed "y":
The following lines will be removed from the configuration:
enable password XJEP6/bAhsOZPahK encrypted
passwd 2KFQnbNIdI.2KYOU encrypted
Do you want to remove the commands listed above from the configuration? [yn]
Ah, the good old default "cisco" passwd entry (who can forget the "KYOU" on the end?) along with the troublesome unknown enable password. I've mangled it to avoid leaking genuine information. After pressing "y" I got the following promising message:
Passwords and aaa commands have been erased.
Rebooting....
This time it actually worked, restoring the enable password to blank!
Out of curiosity I thought I'd check whether the config file was last saved under PIX 6.2 (a long shot, admittedly):
LAB-501# show run
: Saved
:
PIX Version 6.3(5)
<snip>
Er, nope. I can only assume that this little runt of a firewall had previously run 6.2 code and had later been upgraded. I vaguely remember upgrading PIXes in the past and being warned about scary, irreversible changes being made to the flash filesystem - perhaps the file system is a little different between 6.2 and 6.3, but it doesn't bother to overwrite the flash for upgrades between minor releases? Either way, the 6.3 recovery image evidently didn't understand it and 6.2 did.
So there you have it. I suppose in theory you could just start high and work backwards until it succeeds. I've grabbed every recovery image on the page while they're still available - I don't expect Cisco to take them down (they are over a decade old now and still up) but you never know.
There you go. Now there is an answer for the 1 other person in the world who may ever have the same problem trying to revive a completely defunct model of firewall. Long live the PIX!
Showing posts with label password. Show all posts
Showing posts with label password. Show all posts
Wednesday, 9 April 2014
Saturday, 5 October 2013
Be Careful where you use TACACS!
As part of my on-going work to add more and more protocols into my hobby project dechap, I started looking into the workings of TACACS+ today. I was looking to see whether TACACS+ would be a likely candidate as the next attackable protocol. I had in my mind a couple of events from my past that made me suspect that a TACACS+ server couldn't really tell when an incorrect key was in use, other than that the packet decoded to garbage that it was then not able to interpret. If that is the case, it would be very hard to attack the protocol as there is not a straightforward way to tell when you've hit the correct key. I'll let you know when I've figured that out because as I read the protocol spec something else derailed my train of thought.
Like most network engineers I was raised on Cisco's literature and read through plenty of their whitepapers such as this one comparing RADIUS and TACACS+. This document is full of useful facts such as "RADIUS does not allow users to control which commands can be executed on a router and which cannot" (no, Cisco, because for some reason you notched out the ability to do so in IOS) and that RFC compliance doesn't guarantee interoperability. One of the parts I always remembered and believed, in the olden days at least, was the part that says that far beyond the argument of TCP being better than UDP, TACACS+ is more secure than RADIUS due to the way it encrypts the entire message body. I suspect most people just swallow that without chewing, I know I did. Encryption is good, so more encryption must be better.
RADIUS, by comparison, uses CHAP for secure password authentication but makes no attempt to encrypt the parameters within requests and responses. To be fair, these can just be read in plain text straight off the wire. The shared key used when configuring RADIUS is purely an authentication measure - it guards against arbitrary spoofed requests and tampering but does not offer any kind of privacy.
In reality the biggest part of the decision when choosing one or the other will be a "horses for courses" argument. Want to authenticate PPP subscribers with a nice wholesale / retail proxy model? Use RADIUS. Want to authenticate logins to infrastructure devices and authorise specific commands down to the parameter level? Use TACACS+.
RADIUS uses a pre-shared key to authenticate messages going back and forth, but the messages themselves are unencrypted and can easily be read straight off the wire.
TACACS+ relies on the pre-shared key to encrypt everything, including password information. No form of CHAP or similar system is used, so credentials are passed in a reversible form over the wire. It's encrypted, though, so don't worry - unless an attacker knows the key it's all just gibberish. On the positive side of this, the TACACS+ server does not need to store plaintext passwords for the end users and can instead keep one-way hashes on disk meaning that a compromised database is arguably less of an issue. Safe at rest and safe in flight.
Or is it? Think about the typical use case again. TACACS+ is more-or-less always used to authenticate CLI users logging into routers and switches. The key used to encrypt the TACACS+ communications is stored in the device config, either completely in plain text or using (trivially) reversible type 7 encryption. Virtually all devices are left with the password recovery mechanism enabled. Most of the time the key is re-used across every device in the estate since it makes administration easy and, what's the risk anyway?
The thought occurs that many TACACS+ managed devices are in remote locations - far flung or sparsely populated offices, in accessible wiring closets, even (*shudder*) customer sites. Given physical access to a device, it's very possible to make a terminal emulator script to perform a password recovery, dump out the config then reset the config register to its original value within only a couple of seconds more than it takes to double-reboot the device. I know this because I did it many moons ago (I don't have it any more - it was pretty easy to write, though).
If I were an evil adversary who wanted to get some credentials, perhaps a good way would be:
Now you have the administrator username(s) and password(s) in plain text!
Yikes!
Are you sure you still want to run TACACS on that remote box?
Like most network engineers I was raised on Cisco's literature and read through plenty of their whitepapers such as this one comparing RADIUS and TACACS+. This document is full of useful facts such as "RADIUS does not allow users to control which commands can be executed on a router and which cannot" (no, Cisco, because for some reason you notched out the ability to do so in IOS) and that RFC compliance doesn't guarantee interoperability. One of the parts I always remembered and believed, in the olden days at least, was the part that says that far beyond the argument of TCP being better than UDP, TACACS+ is more secure than RADIUS due to the way it encrypts the entire message body. I suspect most people just swallow that without chewing, I know I did. Encryption is good, so more encryption must be better.
RADIUS, by comparison, uses CHAP for secure password authentication but makes no attempt to encrypt the parameters within requests and responses. To be fair, these can just be read in plain text straight off the wire. The shared key used when configuring RADIUS is purely an authentication measure - it guards against arbitrary spoofed requests and tampering but does not offer any kind of privacy.
In reality the biggest part of the decision when choosing one or the other will be a "horses for courses" argument. Want to authenticate PPP subscribers with a nice wholesale / retail proxy model? Use RADIUS. Want to authenticate logins to infrastructure devices and authorise specific commands down to the parameter level? Use TACACS+.
A Slightly More Balanced Comparison
Let's compare the relative merits, security wise of each protocol.Message Encryption
TACACS+, as previously mentioned, encrypts the entire message body using a pre-shared key. It only leaves the header in the clear, so without the key it is only really possible to determine who is client and who is server, plus what kind of messages are being passed (authentication or authorisation, query or response).RADIUS uses a pre-shared key to authenticate messages going back and forth, but the messages themselves are unencrypted and can easily be read straight off the wire.
Credentials
RADIUS relies on CHAP for user credential validation. The NAS sends a "random" challenge to the user, who produces a one-way hash of the challenge data and password (plus some other stuff) and returns that to the NAS. The NAS then sends the challenge and response off to the RADIUS, meaning that the credentials are never sent over the wire in any reversible way. In order to get the password an attacker must capture the challenge and response data then run a dictionary or brute force attack. On the down side, the RADIUS server itself must have a plaintext copy of the password available in order to verify that a response is correct given the challenge. Clearly if the RADIUS server's password database is compromised then things get quite sticky. For proxy RADIUS, the proxy does not need access to plaintext passwords. In summary, passwords are safe in flight but exposed at rest.TACACS+ relies on the pre-shared key to encrypt everything, including password information. No form of CHAP or similar system is used, so credentials are passed in a reversible form over the wire. It's encrypted, though, so don't worry - unless an attacker knows the key it's all just gibberish. On the positive side of this, the TACACS+ server does not need to store plaintext passwords for the end users and can instead keep one-way hashes on disk meaning that a compromised database is arguably less of an issue. Safe at rest and safe in flight.
Or is it? Think about the typical use case again. TACACS+ is more-or-less always used to authenticate CLI users logging into routers and switches. The key used to encrypt the TACACS+ communications is stored in the device config, either completely in plain text or using (trivially) reversible type 7 encryption. Virtually all devices are left with the password recovery mechanism enabled. Most of the time the key is re-used across every device in the estate since it makes administration easy and, what's the risk anyway?
A Really Easy Attack
I'd like to point out I'm not suggesting or endorsing any kind of illegal or immoral behaviour. Even as a joke :)The thought occurs that many TACACS+ managed devices are in remote locations - far flung or sparsely populated offices, in accessible wiring closets, even (*shudder*) customer sites. Given physical access to a device, it's very possible to make a terminal emulator script to perform a password recovery, dump out the config then reset the config register to its original value within only a couple of seconds more than it takes to double-reboot the device. I know this because I did it many moons ago (I don't have it any more - it was pretty easy to write, though).
If I were an evil adversary who wanted to get some credentials, perhaps a good way would be:
- Feign a power cut, on-site work or some other convincing reason for a device to go down
- Take the device off the network (to avoid it phoning home by syslog / SNMP) and perform a quick password recovery / config dump before putting it back to its original condition:
- Stick a sniffer inline between the device and wherever its administrators are
- Call in a fault saying that since the power cut / whatever nothing attached to that router / switch is able to see the network - perhaps leave the LAN side disconnected for authenticity
- Capture TACACS+ packets as the administrators log in to investigate
- Come up with some compelling reason for comms to go down again while the sniffer is taken out
*break*
Readonly ROMMON initialized
program load complete, entry point: 0x8000f000, size: 0xcb80
monitor: command "boot" aborted due to user interrupt
rommon 1 > confreg 0x2142
You must reset or power cycle for new config to take effect
rommon 2 > reset
*snip snip*
Would you like to enter the initial configuration dialog? [yes/no]: no
Press RETURN to get started!
Router>enable
Router#show startup-config | include tacacs
aaa authentication login default group tacacs+ local
aaa authorization exec default group tacacs+ none
aaa authorization configuration default group tacacs+
tacacs-server host 10.4.4.10
tacacs-server key supersecret
Router#conf t
Enter configuration commands, one per line. End with CNTL/Z.
Router(config)#config-register 0x2102
Router(config)#^Z
Router#reload
System configuration has been modified. Save? [yes/no]: no
Proceed with reload? [confirm]
![]() |
| Configuring Wireshark |
![]() |
| Viewing the Decrypted Payload |
Now you have the administrator username(s) and password(s) in plain text!
Yikes!
Are you sure you still want to run TACACS on that remote box?
Labels:
attack,
authentication,
capture,
decode,
decrypt,
key,
password,
recovery,
tacacs+,
tcpdump,
wireshark
Thursday, 3 October 2013
BGP support added to dechap
Hot on the heels of adding the ability to attack OSPF MD5 authentication, I've added BGP support to dechap. It is now possible to feed a pcap file with PPPoE, L2TP, RADIUS, OSPF and BGP packets to the same tool and perform offline dictionary attacks on the authentications within.
As usual, if you're not interested in the theory just skip right to the end for the download link.
BGP authentication uses the MD5 Signature TCP option field, which is defined in RFC 2385. Personally, I found this RFC very vague and it took a lot of iterations to get the technique right. It's particularly fuzzy about what is included in the hash, what isn't and how to present values correctly. I'm hoping to document the process a little more clearly for the next poor guy who tries to implement it as I couldn't find a sufficiently detailed reference anywhere.
RFC 2385 states that the hash must be calculated over the following:
Now, maybe it's just me, but this raised a lot of questions in my mind. Zero padding usually means to fill the trailing space with zeros, but padding the second byte would effectively multiply the protocol number by 256 so should it be a leading zero? Which headers and options are included in the "segment length"? Should the pad bytes be copied with the TCP header?
Through a lot of trial and error I found that:
As usual, if you're not interested in the theory just skip right to the end for the download link.
TCP MD5 Signatures
RFC 2385 states that the hash must be calculated over the following:
1. the TCP pseudo-header (in the order: source IP address, destination IP address, zero-padded protocol number, and segment length) 2. the TCP header, excluding options, and assuming a checksum of zero 3. the TCP segment data (if any) 4. an independently-specified key or password, known to both TCPs and presumably connection-specific
Now, maybe it's just me, but this raised a lot of questions in my mind. Zero padding usually means to fill the trailing space with zeros, but padding the second byte would effectively multiply the protocol number by 256 so should it be a leading zero? Which headers and options are included in the "segment length"? Should the pad bytes be copied with the TCP header?
Through a lot of trial and error I found that:
- The zero padding goes before the protocol number
- The "segment length" includes the TCP header, the TCP options (including room for the MD5 signature option being calculated) and the actual payload data
- The copied TCP header should be 20 bytes long, i.e. includes two padding bytes after the (zeroed out) checksum. The header length remains as-is, including the length of the options.
- The TCP segment data starts immediately after the TCP options and runs to the last byte indicated by the IP length field
- The null byte terminating the password is not passed to the hash algorithm
Checking / Attacking BGP Packets
Using the above method it is straightforward to run a dictionary attack as follows:
Provided the OpenSSL dev libraries are installed it should be possible to simply extract the source code, cd into the directory then run "make". I've only tested this under Ubuntu Linux but there are very few dependancies so I would imagine it will work on most distributions.
The usage is pretty straightforward - there are only two parameters and both are mandatory. Specify your capture file (original pcap format) with the -c flag and your word list with the -w flag. Here's an example:
lab@lab:~/dechap$ ./dechap -w mywords.txt -c bgp.cap
Found password "password1" for TCP from 10.0.0.2 to 10.0.0.1.
Found password "password1" for TCP from 10.0.0.1 to 10.0.0.2.
Found password "password1" for TCP from 10.0.0.2 to 10.0.0.1.lab@lab:~/dechap$
I'm not sure how quickly it runs but it doesn't seem quite as quick as the OSPF version. I suppose BGP packets tend to be a little bigger than OSPF so there's more to hash. You can improve the speed by only including one packet for each source / destination pair in each capture as, at present, it doesn't check for multiple packets between pairs and attacks each instance individually.
If you try this out, please leave a comment on this post with your experiences - good or bad. Any suggestions would also be welcome, particularly for other protocols to attack.
RFC1321 - The MD5 Message-Digest Algorithm
- Start with a sniffed BGP packet (see the original dechap blog post for info on how this is extracted).
- Extract and store the authentication hash (look for option kind 19) for later comparison
- Put together the "pseudoheader" as described above
- Append the TCP header without options
- Append the TCP payload
- Append the candidate password
- Calculate the MD5 hash over the complete data set and compare to the value seen in the sniffed packet. A matching hash indicates a matching password.
Obtaining the Tool
The C source code may be downloaded from: https://github.com/theclam/dechapProvided the OpenSSL dev libraries are installed it should be possible to simply extract the source code, cd into the directory then run "make". I've only tested this under Ubuntu Linux but there are very few dependancies so I would imagine it will work on most distributions.
Using the Tool
As usual - this is for legitimate audit and recovery purposes and must not be used for any kind of malicious activity.The usage is pretty straightforward - there are only two parameters and both are mandatory. Specify your capture file (original pcap format) with the -c flag and your word list with the -w flag. Here's an example:
lab@lab:~/dechap$ ./dechap -w mywords.txt -c bgp.cap
Found password "password1" for TCP from 10.0.0.2 to 10.0.0.1.
Found password "password1" for TCP from 10.0.0.1 to 10.0.0.2.
Found password "password1" for TCP from 10.0.0.2 to 10.0.0.1.lab@lab:~/dechap$
I'm not sure how quickly it runs but it doesn't seem quite as quick as the OSPF version. I suppose BGP packets tend to be a little bigger than OSPF so there's more to hash. You can improve the speed by only including one packet for each source / destination pair in each capture as, at present, it doesn't check for multiple packets between pairs and attacks each instance individually.
If you try this out, please leave a comment on this post with your experiences - good or bad. Any suggestions would also be welcome, particularly for other protocols to attack.
References
RFC2385 - Protection of BGP Sessions via the TCP MD5 Signature OptionRFC1321 - The MD5 Message-Digest Algorithm
Wednesday, 2 October 2013
Offline Attack on MD5 keys in captured OSPF packets
A few months ago I released a tool called dechap which finds PPPoE, L2TP and RADIUS authentications in pcap files and performs dictionary attacks against them. Since writing dechap I've always thought it would be more useful if it were able to do a similar thing with OSPF packets.
Well, the good news is that I've finally got around to adding OSPF support to dechap! Woo and yay! If you just want the tool, scroll straight to the bottom. If you're interested in the theory, read on.
OSPF Authentication Basics
OSPF, or more accurately OSPFv2 as defined in RFC2328, has three options for authenticating incoming packets:
Null: no authentication is performed at all.
Password: a plaintext password is added in the clear to each OSPF packet. If the password contained in an incoming packet matches the one configured locally then the packet is considered valid and is processed, otherwise it is silently ignored.
Message Digest: an MD5 hash is calculated over a combination of the OSPF packet contents and the password. The hash output is then added to the OSPF packet before transmission. When a packet arrives, the receiving router computes an MD5 hash of the packet contents plus its locally stored password. If the calculated hash matches the one attached to the incoming packet then the check passes and the packet is processed; otherwise it is silently dropped.
Note that this is authentication only - in other words the password only serves to verify that the packet contents are authentic. It does not offer privacy, so all the information within the packet is visible in the clear.
OSPF MD5 Authentication Detail
One thing I found unclear in RFC 2328 was exactly what data the MD5 hash was calculated over. The RFC states:
Confusingly, Ref17 refers to RFC1321, which defines the MD5 algorithm. MD5 defines a method to pad the input before the hash is calculated, so it's easy to assume that point (b) refers to that - it doesn't. I spent a couple of hours trying to work out why my hashes were coming out to the wrong value before finally figuring it out. To aid others, I've taken the liberty of rewriting the instructions so that they can be understood by thickos such as myself:
(a) Build the OSPF packet as normal, ensuring that the key number and authentication sequence number are populated. The OSPF length field must contain the total number of bytes in the packet at this point. The checksum must be set to zero.
(b) The authentication key / password in plaintext must be adjusted to exactly 16 bytes, i.e. if the key is longer than 16 bytes then it must be truncated, shorter keys must be padded with null (0x00) bytes until 16 bytes long. The resulting 16 byte "modified authentication key" is then appended to the packet.
(c) The MD5 hash must be calculated over the entire result, i.e. the original OSPF packet plus the 16 byte modified authentication key.
(d) The resulting hash is then written over the modified authentication key in the last 16 bytes of the packet.
Provided the OpenSSL dev libraries are installed it should be possible to simply extract the source code, cd into the directory then run "make".
The usage is pretty straightforward - there are only two parameters and both are mandatory. Specify your capture file (original pcap format) with the -c flag and your word list with the -w flag. Here's an example:
lab@lab:~/dechap$ ./dechap -w mywords.txt -c ospf-bcast.cap
Found password "password1" for user OSPF host 10.1.1.1 key 1.
Found password "password1" for user OSPF host 10.1.1.2 key 1.
Found password "password1" for user OSPF host 10.1.1.1 key 1.
lab@lab:~/dechap$
I haven't tried any serious benchmarks for this but it seems reasonably fast. In a worst case scenario (correct key not present) on my creaky old Athlon XP 2100 it can try 100k passwords in under 100ms.
If you try this out, please leave a comment on this post with your experiences - good or bad. Any suggestions would also be welcome (yes, I know BGP exists).
RFC1321 - The MD5 Message-Digest Algorithm
Input to the authentication algorithm consists of the OSPF packet and the secret key.... and clarifies that:
(a) The 16 byte MD5 key is appended to the OSPF packet.
(b) Trailing pad and length fields are added, as
specified in [Ref17].
(c) The MD5 authentication algorithm is run over the
concatenation of the OSPF packet, secret key, pad
and length fields, producing a 16 byte message
digest (see [Ref17]).
(d) The MD5 digest is written over the OSPF key (i.e.,
appended to the original OSPF packet). The digest is
not counted in the OSPF packet's length field, but
is included in the packet's IP length field. Any
trailing pad or length fields beyond the digest are
not counted or transmitted.
Confusingly, Ref17 refers to RFC1321, which defines the MD5 algorithm. MD5 defines a method to pad the input before the hash is calculated, so it's easy to assume that point (b) refers to that - it doesn't. I spent a couple of hours trying to work out why my hashes were coming out to the wrong value before finally figuring it out. To aid others, I've taken the liberty of rewriting the instructions so that they can be understood by thickos such as myself:
Calculating the MD5 Hash
In order to calculate the correct MD5 hash, the following method should be used:(a) Build the OSPF packet as normal, ensuring that the key number and authentication sequence number are populated. The OSPF length field must contain the total number of bytes in the packet at this point. The checksum must be set to zero.
(b) The authentication key / password in plaintext must be adjusted to exactly 16 bytes, i.e. if the key is longer than 16 bytes then it must be truncated, shorter keys must be padded with null (0x00) bytes until 16 bytes long. The resulting 16 byte "modified authentication key" is then appended to the packet.
(c) The MD5 hash must be calculated over the entire result, i.e. the original OSPF packet plus the 16 byte modified authentication key.
(d) The resulting hash is then written over the modified authentication key in the last 16 bytes of the packet.
Testing / Attacking OSPF Packets
Using the above method it is straightforward to run a dictionary attack as follows:- Start with a sniffed OSPF packet (see the original dechap blog post for info on how this is extracted).
- Extract the original OSPF packet (start immediately after the IP header and continue up to the length specified in the OSPF header)
- Extract and store the authentication hash (the 16 bytes following the packet) for later comparison
- Zero out the checksum
- For each candidate password, pad or truncate to 16 bytes and append to the original OSPF packet.
- Calculate the MD5 hash as described above and compare to the value seen in the sniffed packet. A matching hash indicates a matching password.
Obtaining the Tool
The C source code may be downloaded from: https://github.com/theclam/dechapProvided the OpenSSL dev libraries are installed it should be possible to simply extract the source code, cd into the directory then run "make".
Using the Tool
As usual - this is for legitimate audit and recovery purposes and must not be used for any kind of malicious activity.The usage is pretty straightforward - there are only two parameters and both are mandatory. Specify your capture file (original pcap format) with the -c flag and your word list with the -w flag. Here's an example:
lab@lab:~/dechap$ ./dechap -w mywords.txt -c ospf-bcast.cap
Found password "password1" for user OSPF host 10.1.1.1 key 1.
Found password "password1" for user OSPF host 10.1.1.2 key 1.
Found password "password1" for user OSPF host 10.1.1.1 key 1.
lab@lab:~/dechap$
I haven't tried any serious benchmarks for this but it seems reasonably fast. In a worst case scenario (correct key not present) on my creaky old Athlon XP 2100 it can try 100k passwords in under 100ms.
If you try this out, please leave a comment on this post with your experiences - good or bad. Any suggestions would also be welcome (yes, I know BGP exists).
References
RFC2328 - OSPF Version 2RFC1321 - The MD5 Message-Digest Algorithm
Tuesday, 22 January 2013
RADIUS and L2TP Support Added to "dechap"
This is just a very short message to say that I have enhanced the "dechap" tool mentioned in my previous post. In addition to the original PPPoE support it can now extract and attack CHAP authentications sniffed from RADIUS and L2TPv2 protocols.
The syntax remains exactly the same and it should "just work". The code is available to download at https://www.github.com/theclam/dechap. Please post a comment if you have any feedback or suggestions.
The syntax remains exactly the same and it should "just work". The code is available to download at https://www.github.com/theclam/dechap. Please post a comment if you have any feedback or suggestions.
Monday, 21 January 2013
Recovering CHAP Passwords from Sniffed PPPoE Sessions
In a previous blog post I outlined the theory behind setting up a PPPoE session including PPPoE discovery, LCP, NCPs and, more relevant to this post, the basics of CHAP authentication. At the time I was writing the post I wondered how easy it would be to work back from the CHAP messages on the wire to the original credentials, so I decided to find out.
As a reminder (or a very quick introduction), the CHAP process works something like this:
I wanted the tool to be flexible with regards to encap. Since I work primarily on carrier networks, I get really frustrated by tools that do a job perfectly but only accept untagged, unencapsulated frames. Once you have a packet capture in your hand, realising that it can't be used because it has two VLAN tags and a pair of MPLS labels is a nuisance.
The approach that seemed most sensible was to build a recursive decap function which would take in a (partial) frame plus a "hint" as to what type of header to expect. The function would then check for and record any matching criteria present (i.e. MACs for Ethernet, VLAN ID for 802.1Q - more on this in the next section) before either returning or calling itself on the remainder of the packet with a "hint" derived from the current header.
The initial call to the function passes the entire frame with an "Ethernet" hint. In the Ethernet header, the source and destination MAC addresses are read and stored. The EtherType field contains 0x8100, indicating an 802.1Q VLAN header is next. The function calls itself against the contents of the frame from byte 15 and on with a hint of "VLAN".
Now the function reads and stores the VLAN ID. Since this is the first VLAN we have seen it is stored as the C-VLAN for now. The EtherType is, again, 0x8100 so the function calls itself against bytes 5 and onward using a hint of "VLAN".
Again, the function reads and stores the VLAN ID. Since this is not the first VLAN tag found, the previously known VLAN ID is moved into the S-VLAN field and the value from the frame is stored in the C-VLAN field. This time the EtherType is 0x8864, indicating a PPPoE session header follows. The function calls itself against bytes 5 and onwards using a hint of "PPPoE".
The function now reads and stores the PPPoE session ID (SID). The only valid thing to follow a PPPoE session header is a PPP header, so the function calls itself on bytes 7 and onward, using a hint of "PPP".
The function now simply checks that the protocol ID in the PPP header is 0xC223 for CHAP. If so, it calls itself one last time against bytes 3 and onward using a hint of CHAP.
Finally we are down to the payload. The CHAP message type is checked and:
In order to be considered a challenge / response pair, I decided the following criteria must match:
Additionally, the thought occurred that even with the above details matching, there may be more than one challenge / response pair for the same PPPoE session so a response would have to be paired with the most recent challenge for which the criteria matched. In the program this is achieved by working backwards through the linked list, starting at the response, until a match is found. Data from matching challenge / response pairs are stored in another list for later consumption. If the search reaches the beginning without a matching challenge being found then the response cannot be used and is ignored.
For each challenge / response pair in the list, the next step is to cycle through a list of password guesses. Each candidate password is combined with the authentication ID and challenge data from the captured authentication and hashed. The resulting hash is compared to the one from the captured response and, for those that match, a correct guess is reported. If no password generated a matching hash then the word list does not contain the correct password and this is also reported back.
Provided the OpenSSL dev libraries are installed it should be possible to simply extract the source code, cd into the directory then run "make".
In the future I may add the capability to pull the auths from L2TP or RADIUS interactions but for now only PPPoE is supported. It also assumes that Ethernet control words are not present in MPLS encapsulated traffic.
The usage is pretty straightforward - there are only two parameters and both are mandatory. Specify your capture file (original pcap format) with the -c flag and your word list with the -w flag. Here's an example:
lab@lab:~/dechap$ ./dechap -w mywords.txt -c someauths.cap
Found password "tangerine" for user user1@testisp.com.
Unable to find a password for user user2@testisp.com.
Found password "password1" for user user3@testisp.com.
Found password "Africa" for user user4@testisp.com.
Found password "Frankenstein" for user user5@testisp.com.
lab@lab:~/dechap$
Considering that I've made no effort at all to make the code efficient, I've found the speed pretty good. On my '90s PC, a worst-case run (i.e. where no passwords are found) against 800 auths with 100k candidate passwords, a run still completes inside a minute. I don't think that's bad for parsing 15,000 packets and running 80 million concatenate - hash - compare sequences.
If you try this out, please leave a comment on this post with your experiences - good or bad.
Recap of CHAP Theory
As a reminder (or a very quick introduction), the CHAP process works something like this:
![]() |
| CHAP Authentication |
- The party requiring the opposite peer to authenticate (i.e. "server") sends a CHAP challenge message containing a challenge ID and some unpredictable "random" data.
- The party being authenticated (i.e. "client") concatenates the authentication ID, the password and the challenge data into a single unit, then generates an MD5 hash of that. The resulting hash, plus the client name (user ID or hostname) is passed to the server as a CHAP response.
- The server compares the incoming hash to the value it obtains by performing the same calculation locally and returns a CHAP success or CHAP failure message.
The Attack in Practice
While the process is intuitively simple, as usual there are a few corner cases to cover. Recovering CHAP authentications from a capture file full of other junk requires a certain amount of processing logic, then responses must be re-united with their corresponding challenges before they can be attacked.Gathering CHAP Packets
I wanted the tool to be flexible with regards to encap. Since I work primarily on carrier networks, I get really frustrated by tools that do a job perfectly but only accept untagged, unencapsulated frames. Once you have a packet capture in your hand, realising that it can't be used because it has two VLAN tags and a pair of MPLS labels is a nuisance.
The approach that seemed most sensible was to build a recursive decap function which would take in a (partial) frame plus a "hint" as to what type of header to expect. The function would then check for and record any matching criteria present (i.e. MACs for Ethernet, VLAN ID for 802.1Q - more on this in the next section) before either returning or calling itself on the remainder of the packet with a "hint" derived from the current header.
Worked Example
Let's process the following frame as an example. Data in black are used by the algorithm while data in grey are not.The initial call to the function passes the entire frame with an "Ethernet" hint. In the Ethernet header, the source and destination MAC addresses are read and stored. The EtherType field contains 0x8100, indicating an 802.1Q VLAN header is next. The function calls itself against the contents of the frame from byte 15 and on with a hint of "VLAN".
Now the function reads and stores the VLAN ID. Since this is the first VLAN we have seen it is stored as the C-VLAN for now. The EtherType is, again, 0x8100 so the function calls itself against bytes 5 and onward using a hint of "VLAN".
Again, the function reads and stores the VLAN ID. Since this is not the first VLAN tag found, the previously known VLAN ID is moved into the S-VLAN field and the value from the frame is stored in the C-VLAN field. This time the EtherType is 0x8864, indicating a PPPoE session header follows. The function calls itself against bytes 5 and onwards using a hint of "PPPoE".
The function now reads and stores the PPPoE session ID (SID). The only valid thing to follow a PPPoE session header is a PPP header, so the function calls itself on bytes 7 and onward, using a hint of "PPP".
The function now simply checks that the protocol ID in the PPP header is 0xC223 for CHAP. If so, it calls itself one last time against bytes 3 and onward using a hint of CHAP.
Finally we are down to the payload. The CHAP message type is checked and:
- For challenges, the authentication ID, challenge length and challenge data are stored.
- For responses, the authentication ID, response and client name are stored.
Pairing Up
A CHAP response must be paired up with its respective CHAP challenge, otherwise the maths don't work. In real life there may be several authentications in progress at one time across multiple PPPoE sessions, possibly over multiple different VLANs. Often the CHAP authentication ID is only unique within a PPPoE session. Similarly, the PPPoE session ID only needs to be unique within a broadcast domain so these are often re-used across VLANs. Care must be taken to ensure that the challenge and response really do belong together.In order to be considered a challenge / response pair, I decided the following criteria must match:
- Server and Client MACs
- S & C VLAN IDs (if present)
- PPPoE SID
- CHAP authentication ID
Additionally, the thought occurred that even with the above details matching, there may be more than one challenge / response pair for the same PPPoE session so a response would have to be paired with the most recent challenge for which the criteria matched. In the program this is achieved by working backwards through the linked list, starting at the response, until a match is found. Data from matching challenge / response pairs are stored in another list for later consumption. If the search reaches the beginning without a matching challenge being found then the response cannot be used and is ignored.
Brute Force Password Guessing
For each challenge / response pair in the list, the next step is to cycle through a list of password guesses. Each candidate password is combined with the authentication ID and challenge data from the captured authentication and hashed. The resulting hash is compared to the one from the captured response and, for those that match, a correct guess is reported. If no password generated a matching hash then the word list does not contain the correct password and this is also reported back.
Downloading the Tool
The C source code may be downloaded from: https://github.com/theclam/dechapProvided the OpenSSL dev libraries are installed it should be possible to simply extract the source code, cd into the directory then run "make".
In the future I may add the capability to pull the auths from L2TP or RADIUS interactions but for now only PPPoE is supported. It also assumes that Ethernet control words are not present in MPLS encapsulated traffic.
Using the Tool
The usage is pretty straightforward - there are only two parameters and both are mandatory. Specify your capture file (original pcap format) with the -c flag and your word list with the -w flag. Here's an example:
lab@lab:~/dechap$ ./dechap -w mywords.txt -c someauths.cap
Found password "tangerine" for user user1@testisp.com.
Unable to find a password for user user2@testisp.com.
Found password "password1" for user user3@testisp.com.
Found password "Africa" for user user4@testisp.com.
Found password "Frankenstein" for user user5@testisp.com.
lab@lab:~/dechap$
Considering that I've made no effort at all to make the code efficient, I've found the speed pretty good. On my '90s PC, a worst-case run (i.e. where no passwords are found) against 800 auths with 100k candidate passwords, a run still completes inside a minute. I don't think that's bad for parsing 15,000 packets and running 80 million concatenate - hash - compare sequences.
If you try this out, please leave a comment on this post with your experiences - good or bad.
Subscribe to:
Posts (Atom)





![[Ethernet][VLAN][VLAN][PPPoES][PPP][CHAP]](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzfeDezRzU1M15L9m5rSWEMQbsWN2qoJ4u1_NZIL-i3RsQ4qYFZJvnkgKcZ9VuPn8wjfE8dYnkEmlrY77DkLL313SJsEZQlVQSwxvtDA6xxx7QmCqBhtG-94ZCWSDeVXz3bo_zyh0cnkd2/s1600/PPPoE+Worked+Example+1.gif)
![[VLAN][VLAN][PPPoES][PPP][CHAP]](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-h01a8WlvcLuqpupQ33mQJ77DWnnofLUk3Hh66IpHv2DqTqgOEwWXI8t8aH8iunVjpj93UoMT4QBtRJdqkiEqBAHRHUKrxJtBKw4WilfbfWEgIiF-d7x4X3xW1uJWKRp-8ZegtPoi-Q8e/s1600/PPPoE+Worked+Example+2.gif)
![[VLAN][PPPoES][PPP][CHAP]](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6SSNtBWBTZ8voJHLSiTgPNqmbhvMzpwbuWEVNXnDKA0TqFAb5oom58vokYvSK1VMGoqz3sqzrLRc4HDVufSYjvyFBeIOYMMBZ0AUIgpGXMbZNI-1kUs2C_u6qkD1FLC9Dt4k42IvOQ7Ra/s1600/PPPoE+Worked+Example+3.gif)
![[PPPoES][PPP][CHAP]](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSFZ_enW7Ega8IOKiocuUATjDlnpxiVEXHt7GzR7rWz6LdWRSid3ROClHx9rCehHKM4KBB66r4DEeZzXL9fMm2lKnDEgQq_V31Rf0Fqp1DhL26iEomyfTiQ62T6IMGUJld4GSMiZrmLLzq/s1600/PPPoE+Worked+Example+4.gif)

![[CHAP]](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdYsG-5BT15ZDWIbwXlXkmlgQ7mrS_o-0yxEUJXSFsql6enQu3H1IJvB6EGCaUEpJatcEUSodzLgym4OszC2P4TjNcQ7DUxlPHGoZuSAUrH2oUxh13K3-UQrVWqnUCC5S85-kneC1MNKwa/s1600/PPPoE+Worked+Example+6.gif)