Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.Sign up
Use authenticated encryption #3
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
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:
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.
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.
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
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.:
This will send the server 256 requests. Each message will have a different packet type: 0 through 255. One of these types will be
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 :)
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.
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.