Intro + Use cases
Recently, I posted a blogpost over at NVISO’s blog about hiding data in JPEG’s. After the blog post was written, I decided it was time for myself to start writing a tool to automate the steganography. Initially, this was all I wanted it to do, just hide stuff in images.
After messing around with the concept some more, I decided I was going to challenge myself to code a pretty complex piece of software in C#, using multiple classes and working object-oriented.
And so GG-AESY was born (shout out to Jonas Bauters that came up with the name).
GG-AESY can be found over at GitHub: https://github.com/jfmaes/GG-AESY
GG-AESY does the following things:
- Can hide AES-256 encryption keys or both keys and IV’s (Initialization Vectors)
- Can hide payloads both encrypted and unencrypted
Hiding is done in 2 different ways:
- Random mode: Hiding anywhere possible without breaking the JPEG
- Append mode: appending it to the end of the JPEG.
In addition to the stegano, GG-AESY will also encrypt your file/payload, any extension should work as it’s doing byte encryption.
GG-AESY is also capable of decrypting payloads using the JPEG’s to extract it’s key/IV/payload.
GG-AESY is NOT capable of decrypting and running in memory. This is done ON PURPOSE. GG-AESY itself is not supposed to be weaponized on its own. Feel free to write your own custom loaders in any language you prefer.
If you don’t see the potential of GG-AESY yet, allow me to give some practical examples:
- Write a custom implant that will replace GG-AESY’s decryption logic, this way you can decrypt and launch an AES-256 encrypted payload from memory, without leaving all data hardcoded for forensic analysts to just reverse.
- File exfil, if you are in an environment where you can’t seem to exfil any important data because of protections, you are able to hide them in a JPEG and extract the original content again on your desired destination.
- File infil, if you find yourself in an environment where you cannot download specific extensions, tools, just embed them in the JPEG, and extract them again.
The best part is since it’s written in C#, you are able to run this in your favorite unmanaged CLR loaders such as Cobalt-Strike’s execute-assembly. I have added the latest NuGet package for Costura. Fody, so you’ll need .NET 4.5 on target to load the assembly, or you can choose to downgrade the NuGet package. everything else should be coded to work on a.NET3.5 environment.
To start off, I highly recommend to always use GG-AESY using verbose mode or very verbose mode, if you are not using this in unmanaged loaders, I also recommend always specifying an outfile.
pay attention with very verbose mode though, especially if you are hiding big payloads. as very verbose mode will print the byte array to console.
having said that, let’s dive into the manual for this baby.
_______ _______ ___ _______ _______.____ ____ / _____| / _____| / \ | ____| / |\ \ / / | | __ | | __ ______ / ^ \ | |__ | (----` \ \/ / | | |_ | | | |_ | |______| / /_\ \ | __| \ \ \_ _/ | |__| | | |__| | / _____ \ | |____.----) | | | \______| \______| /__/ \__\ |_______|_______/ |__| V1.0.0 by twitter.com/Jean_Maes_1994 Encryptor and (optional) stegano Usage: -h, -?, --help Show Help -e, --encrypt-only Only encrypts given payload -d, --decrypt decryption mode --ps, --payload-size=VALUE only needed if extracting payload from image for decryption --ef, --encrypted-file=VALUE ENCRYPTION: The outfile for encrypted data DECRYPTION:The inputfile needed to decrypt the payload. -p, --payload=VALUE The path to the payload you want to encrypt -o, --outfile=VALUE The path to the outfile where all important data will be written to (key,iv and encrypted payload) -i, --image=VALUE The image file to hide the key and/or IV in, currently only supports JPEG (JPG) format! --ok, --offset-key=VALUE The offset to search for the key in image (in decimal) --okh, --offset-key-hex=VALUE The offset to search for the key in image (in hex) --oIV, --offset-IV=VALUE The offset to search for the IV in image (in decimal) --oIVh, --offset-IV-hex=VALUE The offset to search for the IV in image (in hex) --op, --offset-payload=VALUE The offset to search for the payload in image (in decimal) --oph, --offset-payload-hex=VALUE The offset to search for the payload in image (in hex) -v, --verbose write all the good stuff to console,recommended you actually always use this. --vv, --very-verbose prints encrypted payload array to console -k, --key=VALUE in case you want to use your own key value! --IV, --initialization-vector=VALUE in case you want to use your own IV --rk, --random-key-mode will hide your key in a random insertion point in the provided image, without breaking said image. will print the offset to console --ra, --random-all-mode will hide both Key and IV in a random insertion point of the image. --ak, --append-key-mode will hide the key at the end of the image file --aa, --append-all-mode will hide the key and the IV at the end of the image file. --ap, --append-payload-mode will hide the payload at the end of the image file --rp, --random-payload-mode will hide the payload at a random insertion point. --apu, --append-payload-unencrypted appends your payload without crypto, useful for very quick and dirty data exfil.
-e or –encrypt-only: Will only encrypt a given payload (-p) will write key/iv to console if using verbose mode, will write key/iv/payload into an outfile if using the outfile (-o) flag, and finally will write the bytestream to another file if using the encrypted file (-ef) flag.
-d or –decrypt: Decryption mode, you can specify the decryption parameters using offsets (in case you have hidden key or key and IV in a JPEG). Offsets are passed to the program using either the offset-key (-ok) or offset-key-hex (-okh) flags, you can use “-” as separators or just paste in the hex without any separators, both will work fine. IV’s work the same way using -oIV and -oIVh flags.
Alternatively, you can give the IV and Key directly (in case they are not hidden in a JPEG), using the key (-k) and initialization-vectors (-IV) flags. As with the offset flags, “-” can be used as a separator, GG-AESY accepts both ASCII and byte values.
In order to decrypt, you’ll also need to specify an encrypted file (-ef).
Should you have hidden a payload in a JPEG and wish to decrypt it, you’ll have to specify the payload size (-ps) so GG-AESY will extract all data correctly without false positives/false negatives 🙂 .
-u or –unpack: Will unpack unencrypted appended payloads (=apu mode) from the JPEG.
If no key/iv is provided, random key/iv’s will be used to encrypt your data. All stego modes will require you to pass GG-AESY a JPEG image (-i). If you have specified an outfile (-o) to save your important information about the crypto ( such as key, iv, payload), all stego modes will also add the injection places in this file.
-rk or –random-key-mode: This Stego mode will hide your AES-256 key at a random injection point.
-ra or –random-all-mode: This Stego mode will hide both your AES-256 key and IV at a random injection point, both injection points can be the same (it’s a random selection process), in this case, the key and IV will be injected back to back.
-ak or –append-key-mode: This Stego mode will append the AES-256 key at the end of the JPEG.
-aa or –append-all-mode: This Stego mode will append both AES-256 key and IV at the end of the JPEG.
-ap or –append-payload-mode: This Stego mode will append the encrypted payload bytestream to the end of the JPEG.
-rp or –random-payload-mode: This Stego mode will inject the encrypted payload bytestream at a random injection point. CAUTION: This only works if your payload does not exceed 65,535 bytes, which is about 65kb, if you try a larger payload, an error will be thrown in your face. Needless to say, this mode is practically useless 🙂
-apu or –append-payload-unencrypted: This Stego mode will append the payload bytestream as-is to the end of the JPEG.
DISCLAIMER: This tool is in EARLY BETA. It’s not been battle tested yet, so please submit improvements through PR’s or raise issues in case of bugs. However, due to my current workload, active development on this tool from my end will not be possible at this time.
This does not mean I’m abandoning this project though 🙂