Saturday, September 24, 2022

Easy shellcode encryption and decryption using AES in C/C++

 I'm writing this blog post as I came across this problem myself while trying to encrypt and decrypt my shellcode while writing malware.

As there are lots of easy to implement encryption and decryption mechanisms like XOR, they aren't resilient enough. Even though with proper XORring of the shellcode; while many AVs and EDRs may be bypassed, the shellcode can easily be decrypted using manual trial-and-error technique. Hence, the best way to go about encrypting the shellcode would be using the top-of-the-shelf encrypting algorithm like AES. Using AES algorithm to encrypt and decrypt shellcode using Windows Cryptography API (https://learn.microsoft.com/en-us/windows/win32/seccng/typical-cng-programming) is fine, they can easily be hooked by EDRs and all the work we did would be for naught. 

The best way to protect our shellcode would be using a local implementation of AES which wouldn't be hooked by EDRs and at the same time protect from spying and static reversing.

For this reason, I'm choosing to use the `tiny-aes-c` library written by kokke (https://github.com/kokke/tiny-AES-c). There's only a header and the implementation file to import to our own project and we're ready to go. The only complain I have with this library is that it doesn't automatically pad our keys, IV and shellcode to the block size (16 bytes / 128 bits). This means we need to pad all of our stuff by ourselves. Well any ways lets make it all clear by encrypting some sample data using AES-128.

The skeleton code for using the `tiny-AES-c` would look something like this:


unsigned char key[] = "xxxxxx";

unsigned char iv[] = "\x00\x01\x02\x03\x04\x05";

unsigned char shellcode[] = "\x2e\x51\x54\xf6\xa5\xbf\xb7\xe5\x06\x61\x62\x76\x4e\xe1\xa9\x01\xb9\x1f\x68\xfe\xb9";

struct AES_ctx ctx;

AES_init_ctx_iv(&ctx, key, iv);

AES_CBC_encrypt_buffer(&ctx, shellcode, sizeof(shellcode) - 1);

printf("Encrypted shellcode:\n");

for (int i = 0; i < sizeof(shellcode) - 1; i++) {
printf("\\x%02x", shellcode[i]);
}


Well, the code above is fine with a few catches. First is that we need to make sure our key and the initialization vector (iv) are both 16 bytes in length. This is because the AES algorithm and the tiny-aes-library encrypts data in blocks of 16 bytes using the key and IV.

unsigned char key[] = "asdfghjklzxcvbn";

unsigned char iv[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e";

As you can see, I've declared both the variables with 15 characters. This is because a end of string \x00 is added automatically to denote end of a char[] variable by the compiler. Therefore, it makes it 16 bytes in total.

Now, we also need to pad our shellcode to a multiple of 16 bytes too because of the requirement of the library, however this can get bothersome when we have to keep changing our shellcodes for various reasons. For this specific reason, I've created two functions to aid in using tiny-aes-c library.

The first function is:


int calculatePaddingLen(int shellcode_len) {

	int shellcode_spill = shellcode_len % 16;

	int fillers_required_len = 16 - shellcode_spill;

	return fillers_required_len;

}


The code is self explanatory. It basically calculates the padding length requires beyond the shellcode length to make the shellcode a multiple of 16 bytes.

The second function is:


unsigned char* padShellcode(unsigned char* shellcode, int shellcode_len) {

	int fillers_required_len = calculatePaddingLen(shellcode_len);

	int final_shellcode_size = shellcode_len + fillers_required_len;

	unsigned char* new_shellcode_memory = (unsigned char *)malloc(final_shellcode_size);

	memcpy(new_shellcode_memory, shellcode, shellcode_len);

	int x = 0;

	for (x = shellcode_len; x < shellcode_len + fillers_required_len; x++) {

		new_shellcode_memory[x] = '\x00';

	}

	return (unsigned char*)new_shellcode_memory;

}



This function basically allocates new memory with the new length required to make the shellcode a multiple of 16 bytes and returns a pointer to the memory.

Keep in mind that both of the functions expect the actual length of the shellcode and NOT the length of the variable, which is shellcode + \x00 (end of string byte).  This is why we are remove the size of the shellcode by 1.

In case if you're wondering what happens if we don't pad the shellcode properly and do-not use proper lengths, the encrypted message and/or the final decrypted data will NOT result in the desired output. This is because the library uses due to its exact 16 byte encryption scheme. If we use a 18 byte shellcode then the next 16 byte multiple will be 32 bytes. Hence the rest 14 bytes that the library uses will be taken from the end of our shellcode memory boundary resulting in the usage of random stack data which is not controlled by us resulting in incorrect encryption result. If you don't believe me feel free to go ahead and try it to test your luck :D 

So now the final padded and encrypted code to use the tiny-aes-c library will look something like:


unsigned char key[] = "K@fatm2040qwerp"; // 15 bytes plus \x00 = 16 bytes, 128 bits
unsigned char iv[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"; // 15 bytes plus \x00
unsigned char shellcode[] = "\x2e\x51\x54\xf6\xa5\xbf\xb7\xe5\x06\x61\x62\x76\x4e\xe1\xa9\x01\xb9\x1f\x68\xfe\xb9"; // random number of bytes

int shellcodeSize = sizeof(shellcode);
shellcodeSize = shellcodeSize - 1; // need to do this to remove the last \x00 end of string byte

unsigned char* paddedShellcode = padShellcode(shellcode, shellcodeSize);
int paddingLength = calculatePaddingLen(shellcodeSize);
int finalShellcodeLength = shellcodeSize + paddingLength;

struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CBC_encrypt_buffer(&ctx, paddedShellcode, finalShellcodeLength);
printf("Encrypted buffer:\n");

for (int i = 0; i < finalShellcodeLength; i++) {

	printf("\\x%02x", paddedShellcode[i]);

}

// remember to free the allocated memory bruvv

free(paddedShellcode);


All done! We can now just copy the padded and printed bytes and paste it into our malware injector which decrypts and injects the shellcode.


Just for completion's sake, the decryption code would look something like:


unsigned char key2[] = "K@fatm2040qwerp"; // 15 bytes plus \x00 = 128 bits

unsigned char iv2[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"; // 15 bytes plus \x00

unsigned char shellcode_enc[] = "\x3d\x78\x6c\x5d\xa0\x55\xe5\xe1\x14\xb0\x51\xd7\x65\x6b\x4c\x20\x77\x7f\x07\x22\xcc\xa4\xec\xf7\x5e\xc8\x09\xdd\x97\x71\xa6\x64"; // This is the encrypted shellcode from our code above.

int encShellcodeSize = sizeof(shellcode_enc) - 1;

struct AES_ctx ctx2;

AES_init_ctx_iv(&ctx2, key2, iv2);

AES_CBC_decrypt_buffer(&ctx2, shellcode_enc, encShellcodeSize);

printf("Decrypted buffer:\n");

for (int i = 0; i < encShellcodeSize; i++) {

	printf("\\x%02x", shellcode_enc[i]);

}

Make sure the key and IV of both the encryption and decryption code is the exact same, otherwise the encryption and decryption won't occur properly.

And there we go. We now have a clear understanding of encryption and decryption using the `tiny-aes-c` library with all the gotchas and its fixes.

The full code can be found in this gist: https://gist.github.com/emalp/124e71c5b0497110368a78fcc46863ea

Monday, May 30, 2022

May - The month of walkthroughs

 As you can see, all of the blog posts this month have been walkthroughs from HackTheBox.

All of these are actually just a memory dump of the work I did when I was doing a subject called "Security Engineering" when I was back at uni. I had to do a HackTheBox machine every week and write a walkthrough on it. It still had the documents in my laptop somewhere so I decided to dump all of those into my blog.

I hope this will help someone struggling to pwn the box or someone looking for a method different than theirs. Cheerss!

HTB Walkthrough - Sniper

 Over the weekend I worked on the box: Sniper.

Let’s dive in right away on how I did it!


NOTE: This is not meant to be a tutorial but rather a walkthrough on how I did it.


Let’s start pwning the awesome box

The IP address of the box is: 10.10.10.151


Like every other pentesting and pwning methodology, let’s start with a simple nmap scan of the box (10.10.10.151):



As we can see, we have the SMB ports, NFS port and HTTP ports open.

The HTTP port looks like the most prominent one, so let's dive into that!


After looking through the (not so interesting) main page, I decide to run gobuster through it to get all the interesting directories.



Gobuster gives us a list of these interesting dirs, as /user and /blog are the ones present in the home page too, so I decided to check them out.


I wander through the /user part of the site for a long time, as it presents what seems like a hackable login page. However, I couldn’t login or find any kind of vulnerability in it.



So, I give up on this part of the directory and move on to look at /blog.


As soon as I visit /blog, I find an interesting finding. It seems like a LFI! However, when I try to include pages/files from other directories; it fails.



So, after a while however I remember that there are ports 139 & 445 open! That means I can possibly include files from other open smb shares. I do just that. I place a simple <shell.php> in my smb share and try to require that file from the link and it works! So, I place netcat (nc.exe) in my smb share and try to run that through the shell.php.


The simple shell.php just executes commands from the cmd get request parameter.



This gives me the initial shell! Hurray!!!



As, we can see I got the reverse shell. And also from the name of my user ‘iusr’, I happen to be a service user. So, I check my privileges and I do have all the service privileges. 

I think of using one of the potato exploits but as the Operating System I’m running is Windows Server 2019, they might not be effective for this machine. Hence, I resort to the other new priv esc exploit, PrintSpoofer.


I move the PrintSpoofer into my smb share and try to get another reverse shell by executing nc.exe. Also note that I couldn’t create any files anywhere in the system as it kept giving me access denied; therefore I only used my open smb share and did not place any files anywhere in the system (good hiding & no footprints!)



So I got system access in my listening nc.



Boom! One system down!


When I looked online after I pwned the box, it seems like there were also other multiple ways of pwning the box except for straight up abusing the service privileges. However, I (by luck) did the simplest one! Looking forward to pwning other boxes.


HTB Walkthrough - Postman

 Postman is an easy rated box in HTB. Let’s see for ourselves if it’s easy or not.

Starting out with our regular, nmap scanning:



As we can see, we have port 22, 80, 6379 and 10000 open.

We know that port 22 is for SSH, so let’s leave it for now.


Let's look at port 80 for now.

We see this home page after navigating to the webpage.


However, even after trying a lot and fiddling around with gobuster; I couldn’t find any handle to go through. So let's move on to see if we can do something with the remaining ports.

Port 6379 caught my eye as it’s a redis port. I know from experience that redis by default has no password or username and anyone can login by default. I also know that modern webmin versions (located at port 100000) don’t have any RCE and are pretty secure. So, redis looks like our best bet.

As I suspected, after some trying redis looks like it does not have any password! Hurray.


Now, we can try and carry out a multitude of techniques to try and get a RCE.

The first thing I always try in this scenario is try and upload an id_rsa.pub into authorized_keys; basically exploiting SSH.


After generating my id_rsa and id_rsa.pub using openSSH. I’m ready to upload these into the remote system.

First thing to note is, normally the /var/lib/redis is set as the home directory by default into redis so uploading our id_rsa.pub (public key) values into /var/lib/redis/authorized_keys looks like a good way to start.

Yaaay! Looks like our public key was successfully uploaded!

Let’s try logging in through SSH now.



Everything looks good till now.

However, we are now using the redis user, who doesn’t really have any power in the system. Let’s look for other users and try to escalate privileges.


Alright, the only user we have in the system is called ‘Matt’. Let’s try looking and enumerating.


I eventually found a file called id_rsa.bak in the /opt directory. I copy over the file into my local machine and take a look at it.



I immediately notice that this file is protected by some sort of password. Let’s put this into ssh2john and generate a crackable file, crackable by johnTheRipper. After doing that and running johnTheRipper using the famous rockyou.txt wordlist, I immediately get a valid password!



However, when I tried to SSH using the cracked id_rsa and the correct passphrase, I still couldn’t login!



I later found out that the passphrase itself was the password. So a simple ‘su’ command did the trick!



All good till now. 


Now, remembering the open port 10000 we found in our nmap scan, we know that webmin always runs as root. It’s also used to manage the systems, so we should be able to login as Matt. Let’s see if it works.



Yes!, we can login to webmin using the user Matt! So, we can easily use the /password_cgi exploit where most webmin versions are vulnerable.

Try an exploit I found here: https://github.com/KyleV98/Webmin-1.910-Exploit




Yessss! We’ve finally rooted the box.



HTB Walkthrough - Hawk

 Hawk is a medium rated box in HackTheBox. Let’s see how we go.

As usual, let’s first start with a simple nmap scan.



We can immediately see that we have anonymously available FTP, a web server on port 80 and an H2 database running on port 8082.

Let’s see what we have available on the openly available H2 Server.


We find a hidden file inside of FTP.


Downloading the file and looking at the encoded text, it looks like base64. Decoding the base64 file gives us gibberish so it must be a binary file. 



We see that it’s a file encrypted using openssl and a salted password.

To decrypt this we need to first know which algorithm was used to encrypt it. 

Following this tutorial: https://myexperiments.io/finding-cipher-algorithm-encrypted-file.html, I tended to focus that maybe my file was also encrypted using the same algorithms; if it wasn’t I was going to try other popular encryption algorithms.


Now, bruteforcing the passwords using bruteforce-salted-openssl (openly found in github).



Image, might be hard to read; but I found a password ‘friends’.

Finally, unencrypting the encrypted file using openssl, I get a plaintext.



It says to use the password ‘PencilKeyboardScanner123’ in the portal. Okay, we need more context on where to use this password and where this ‘portal’ is.


Moving forward and looking at the open port 80 that we found in our nmap scan, I find a drupal website. So this must be the portal the text file was talking about. Let’s try the simple username admin and the given password.



This seems to work! Nice. Now I can do many things to try and get a reverse shell.

Let’s first traverse to modules and enable php filtering so that we can run custom php code.



Good, now lets run a reverse shell php code by adding a basic content.


The reverse shell php code was taken from: https://github.com/pentestmonkey/php-reverse-shell


Let’s preview the code and see if we get a revshell back.



Yes! We got a reverse shell back!


Good going, Now when we look at the running processes, we can see that the H2 DB that was running on port 8082 is actually running as root. Maybe we can do something and escalate our privileges to root.


I notice this exploit: https://www.exploit-db.com/exploits/45506 

Looking back at the version, the version matches too! Let’s try and see if this exploit works and gives us root.



Yep, it works of-course! Talk about being lucky haha.

Hawk has also been rooted!


HTB Walkthrough.- Feline

 Feline.

This is a HARD rated box in HackTheBox. This is going to be one of the rare hard boxes as they take a lot of time and effort and constitute a lot of my very important days. However, let’s see how we go.


As usual, starting with our nmap scan.



We can see that we only have port 8080 open, where we have Apache Tomcat 9.0.27 running and a SSH port 22 is also open.



We see this on our home page. We can also see some other tabs in the menu; one of which is the services tab. Let’s click and see where we go.



Hmm, we can upload any type of file in here. However, I can’t seem to run any of the uploads or get any type of response back. Weird. We know the tomcat version, so let's see if there’s any public exploits out there.


I immediately find a remote code execution for this version number: https://github.com/PenTestical/CVE-2020-9484



However, the normal bash exploit didn’t seem to work for me. So I changed the exploit to fit my needs and did some custom exploitation.



I changed the exploit to download a .jar file from my server and then subsequently run it.

I generated a reverse shell jar file using msfvenom.



After running the exploit, I got my first reverse shell!



Ok nice, we’re in a shell now.

Now, let’s try and escalate our privileges. Let’s see if there are any ports open locally and accessible only locally.



We can see that port 4505 and port 4506 are present and only accessible locally. After a quick search of google, I now know that these are ports used by the ‘Salt’ program. 

Let’s see if there are any publicly available exploits for Salt.


I find this program here: https://github.com/rossengeorgiev/salt-security-backports/blob/master/salt-cve-check.py to check if the current Salt version is exploitable. But first let’s forward the local ports to be accessible through my pwing machine.



After I run this exploit locally, I find that the salt program running is indeed vulnerable.


Then, after searching for exploits, this github exploit looks promising: https://github.com/jasperla/CVE-2020-11651-poc


I create a simple rev.py python reverse shell and try to execute it using salt.



I then get back a reverse shell!



Nice. Now looking at my username and the machine name, it looks like I’m in a docker container.

I do some more enumeration and finalise that I indeed am in a docker environment.

So, let's look for ways to break out of the current docker container. We know that docker runs as root, so if we find a way to break-out we’ll be root in the main host OS.


After some enumeration, I found a docker.sock unix socket inside /run. Docker.sock can be used to easily break out of docker by creating a new container.


Following this tutorial: https://secureideas.com/blog/2018/05/escaping-the-whale-things-you-probably-shouldnt-do-with-docker-part-1.html


I create a container.json file and start with my docker breakout.



YES! We’ve finally rooted! Docker breakout was successful and we got root.


HTB Walkthrough - Celestial

 Celestial


Okay, so let’s get going into another of the boxes. This time we are going to hack “Celestial”

Celestial is a medium rated box running on Linux. So, let’s see what’s interesting.


As usual, we start with a nmap scan.



As we can see we have port 3000 open and it’s the only port that’s open and it’s running the NodeJS Express framework.


After I go into the page, I can’t see anything. However, after I refresh it again; I see this:


It says, ‘Hey Dummy’. So, I think Dummy is our name and is being passed around in some form.

So, I decided to look at our cookies using burp and just as I thought.



Our cookie contains a base64 encoded variable. I’m guessing this when decoded, contains our value. So I proceeded to decode this.


Exactly as I had guessed;

It is a json variable encoded into base64. Also, we know from the nmap scan that it’s using the express framework. 

I’m clearly looking at a deserialization vulnerability right here. I just need to replace the username with my own value which will get deserialized. I found later that the username will display error when it detects the type of username variable is not string but runs the command anyway. So with a few tweaks here and there I created a perfect string that goes in the username variable. 

Well, might be a bit hard for the eyes to see; but that’s part of the game if you want to replicate this ;)


So, I encode this into base64 and send it.



Just as I had hoped, the ‘a’ returned and everything else ran as command. I should have received a reverse shell into my nc listener.


Bam, there you go!


Now time to get root.


I see a peculiar output.txt in the home folder for the sun user.  Upon inspection, I see



Seems like some sort of script is running and producing this output.


After I try and look for the user.txt file, I find it inside Documents alongside another file.



Okay so, seems like the output from this script was being redirected to output.txt

So there definitely is a cron job happening behind the scenes. So investigate further I use pspy to see what’s happening.



Okay, so root runs script.py then immediately chowns it to the sun user. That means I can replace my own script.py which does some work as root. So I decided to just copy /bin/sh and set the setuid bit on it.



Then it’s the waiting game. Aaand Boom, I get the setuid shell in /tmp. I run the file with /tmp/sh -p and I am root!



Done!


Easy shellcode encryption and decryption using AES in C/C++

 I'm writing this blog post as I came across this problem myself while trying to encrypt and decrypt my shellcode while writing malware....