New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use authenticated encryption #3

Merged
merged 1 commit into from Aug 9, 2015

Conversation

Projects
None yet
3 participants
@joncave
Contributor

joncave commented Aug 8, 2015

Even though the agent to server communications are encrypted they are still malleable and vulnerable to attack.

The easiest attack is to trick a server into forgetting an agent. Take an encrypted message sniffed from the network and send it to the server 256 times with the first byte replaced so that it has all values 0 through 255. The server sees 256 packets with 256 different types, one is guaranteed to be TASK_EXIT.

Because the padding isn't verified there isn't an opportunity for a traditional padding oracle attack. However, there are ways to get the server to decrypt portions of an encrypted packet for you. The only method for doing this I've worked out isn't very efficient or effective though.

Notes some choices I made:

  • MD5 to save space in messages over something better, e.g. SHA256
  • Double HMAC to prevent timing attacks on the server. Python provides a compare_digest() method but it was only introduced in 2.7.7 (Kali is currently 2.7.3)

This should also probably be extended to the stager. I can do that in a follow up commit if somebody signs off on my powershell looking sane :)

I've only given some cursory testing with basic functionality as I haven't had an opportunity to get familiar with Empire.

@HarmJ0y

This comment has been minimized.

Show comment
Hide comment
@HarmJ0y

HarmJ0y Aug 8, 2015

Contributor

As we don't have our formal spec document completed yet, let me try to elaborate on a few more of the underlying features to make the process a bit more transparent.

There is a randomized IV used for the CBC AES encryption underneath that's appended to the beginning of each tasking and response packet.

There's also some basic anti-replay build in. On one of the last steps of negotiation, the server sends the current server epoch time to the client which is used as a delta. This epoch/counter is embedded in every packet, and a 5 minute sliding window is kept on the agent as well as on the server side, where non-compliant taskings/responses should be discarded.

All that said, we're not crypto experts, so appreciate the input. Authenticated encryption seems like it would be a good addition- we'll examine this in depth over the next few days to make sure it makes sense for the current process. If any of the notes above affect the assumptions you've made with the pull request let us know.

Contributor

HarmJ0y commented Aug 8, 2015

As we don't have our formal spec document completed yet, let me try to elaborate on a few more of the underlying features to make the process a bit more transparent.

There is a randomized IV used for the CBC AES encryption underneath that's appended to the beginning of each tasking and response packet.

There's also some basic anti-replay build in. On one of the last steps of negotiation, the server sends the current server epoch time to the client which is used as a delta. This epoch/counter is embedded in every packet, and a 5 minute sliding window is kept on the agent as well as on the server side, where non-compliant taskings/responses should be discarded.

All that said, we're not crypto experts, so appreciate the input. Authenticated encryption seems like it would be a good addition- we'll examine this in depth over the next few days to make sure it makes sense for the current process. If any of the notes above affect the assumptions you've made with the pull request let us know.

@joncave

This comment has been minimized.

Show comment
Hide comment
@joncave

joncave Aug 8, 2015

Contributor

I was in a bit of a rush earlier, so didn't take the time to write out a full description...

CBC mode doesn't provide any integrity validation, so modifications to the ciphertext are not prevented when it comes to decryption. Because of the way CBC works, XORing a byte into a block of ciphertext causes the same change to the corresponding byte in the next block of plaintext (as well as corrupting the modified block).

In my example I change the first byte of the ciphertext (i.e. the first byte of the IV) in order to change the first byte of the plaintext (i.e. the type of the packet). The first block of plaintext is calculated as P = IV ^ D(C). If the IV is modified by X we end up with (IV ^ X) ^ D(C) = P ^ X. So you see we get a targeted change to P. Here is a simple Python script as a demo:

import requests
import sys

ciphertext = sys.argv[3].decode("hex")
cookies = {"SESSIONID": sys.argv[2]}
for i in range(0, 256):
    dos = chr(i) + ciphertext[1:]
    requests.post(sys.argv[1], cookies=cookies, data=dos)

Pass the script the listener URL, the session ID, and an encrypted message that you've sniffed from the network in the past 10 minutes, e.g.:

$ python dos.py http://192.168.56.100:8080/login/process.jsp WRXHRVLAWEMBTKGH f9341f6e69be...

This will send the server 256 requests. Each message will have a different packet type: 0 through 255. One of these types will be TYPE_EXIT. So we will trick the server into removing the target session from its database and it ignores any further checkins from the agent.

Since I can guess the contents of the counter if I know the time the packet was sent I can tweak it by modifying the IV (assuming there is only one packet in the message). This means that you don't necessarily have to use a sniffed message within the 10 minute window.

Full decryption of a message may be possible. Often unauthenticated CBC mode is vulnerable to a padding oracle attack which allows full decryption, which can then be leveraged to perform blind encryption without knowledge of the key. In Empire this is not so easy as the padding is not strictly validated, so doesn't leak as much information. There are some tricks that can be played to do partial decryption, but from my brief look I think it's a relatively limited or inefficient attack. However, it's not ideal :)

Contributor

joncave commented Aug 8, 2015

I was in a bit of a rush earlier, so didn't take the time to write out a full description...

CBC mode doesn't provide any integrity validation, so modifications to the ciphertext are not prevented when it comes to decryption. Because of the way CBC works, XORing a byte into a block of ciphertext causes the same change to the corresponding byte in the next block of plaintext (as well as corrupting the modified block).

In my example I change the first byte of the ciphertext (i.e. the first byte of the IV) in order to change the first byte of the plaintext (i.e. the type of the packet). The first block of plaintext is calculated as P = IV ^ D(C). If the IV is modified by X we end up with (IV ^ X) ^ D(C) = P ^ X. So you see we get a targeted change to P. Here is a simple Python script as a demo:

import requests
import sys

ciphertext = sys.argv[3].decode("hex")
cookies = {"SESSIONID": sys.argv[2]}
for i in range(0, 256):
    dos = chr(i) + ciphertext[1:]
    requests.post(sys.argv[1], cookies=cookies, data=dos)

Pass the script the listener URL, the session ID, and an encrypted message that you've sniffed from the network in the past 10 minutes, e.g.:

$ python dos.py http://192.168.56.100:8080/login/process.jsp WRXHRVLAWEMBTKGH f9341f6e69be...

This will send the server 256 requests. Each message will have a different packet type: 0 through 255. One of these types will be TYPE_EXIT. So we will trick the server into removing the target session from its database and it ignores any further checkins from the agent.

Since I can guess the contents of the counter if I know the time the packet was sent I can tweak it by modifying the IV (assuming there is only one packet in the message). This means that you don't necessarily have to use a sniffed message within the 10 minute window.

Full decryption of a message may be possible. Often unauthenticated CBC mode is vulnerable to a padding oracle attack which allows full decryption, which can then be leveraged to perform blind encryption without knowledge of the key. In Empire this is not so easy as the padding is not strictly validated, so doesn't leak as much information. There are some tricks that can be played to do partial decryption, but from my brief look I think it's a relatively limited or inefficient attack. However, it's not ideal :)

sixdub added a commit that referenced this pull request Aug 9, 2015

Merge pull request #3 from joncave/authenticated_encryption
Update of encryption scheme uses to include integrity checking. Merge from joncave/authenticated_encryption

@sixdub sixdub merged commit db1bc92 into EmpireProject:master Aug 9, 2015

@sixdub

This comment has been minimized.

Show comment
Hide comment
@sixdub

sixdub Aug 9, 2015

Contributor

The code looks good and I appreciate the in depth write up! Pretty neat to see the attack and work through it (also a stupid mistake on our part).

I accepted the pull request. I am doing a little bit more reading on the use of the same session key for AES-CBC and CBC-HMAC... I know that using the same key could introduce a vulnerability and I want to be sure it checks out. If you find an additional vuln, please feel free to submit an issue or pull request.

Contributor

sixdub commented Aug 9, 2015

The code looks good and I appreciate the in depth write up! Pretty neat to see the attack and work through it (also a stupid mistake on our part).

I accepted the pull request. I am doing a little bit more reading on the use of the same session key for AES-CBC and CBC-HMAC... I know that using the same key could introduce a vulnerability and I want to be sure it checks out. If you find an additional vuln, please feel free to submit an issue or pull request.

@joncave

This comment has been minimized.

Show comment
Hide comment
@joncave

joncave Aug 9, 2015

Contributor

No problem.

I forgot to mention the key reuse in my list of choices above. You're right, in general it is best practice to use different keys for encryption and MACing. The classic example of where the same key leads to problems is the use of AES-CBC and CBC-MAC. However, there are cases where this doesn't apply (e.g. CCM mode). Since HMAC is being used for authentication here there isn't believed to be an issue. I went with the same key for simplicity in the first pass at introducing authenticated encryption. If you would like to use different keys just to be safe you can derive two new keys from the initial session key: one for encryption, and one for authentication. HKDF would be a good way to do this.

Contributor

joncave commented Aug 9, 2015

No problem.

I forgot to mention the key reuse in my list of choices above. You're right, in general it is best practice to use different keys for encryption and MACing. The classic example of where the same key leads to problems is the use of AES-CBC and CBC-MAC. However, there are cases where this doesn't apply (e.g. CCM mode). Since HMAC is being used for authentication here there isn't believed to be an issue. I went with the same key for simplicity in the first pass at introducing authenticated encryption. If you would like to use different keys just to be safe you can derive two new keys from the initial session key: one for encryption, and one for authentication. HKDF would be a good way to do this.

@HarmJ0y

This comment has been minimized.

Show comment
Hide comment
@HarmJ0y

HarmJ0y Aug 9, 2015

Contributor

This is freakin' amazing! Thanks so much for incredibly detailed writeup and pull request. Appreciate the education for my crypto-newbness :)

Contributor

HarmJ0y commented Aug 9, 2015

This is freakin' amazing! Thanks so much for incredibly detailed writeup and pull request. Appreciate the education for my crypto-newbness :)

@HarmJ0y

This comment has been minimized.

Show comment
Hide comment
@HarmJ0y

HarmJ0y Aug 15, 2015

Contributor

Also, if you're cool with adding the logic to the stager as mentioned, please feel free :)

Contributor

HarmJ0y commented Aug 15, 2015

Also, if you're cool with adding the logic to the stager as mentioned, please feel free :)

@enigma0x3 enigma0x3 referenced this pull request Aug 27, 2015

Closed

FIPS enforcement woes #35

rvrsh3ll pushed a commit that referenced this pull request Jul 25, 2017

xorrior pushed a commit that referenced this pull request Feb 27, 2018

xorrior pushed a commit that referenced this pull request May 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment