Last updated on September 18, 2020
This is the third post on the post-exploitation method based on code caves. In the first part I showed you how to create a basic code cave in an executable to introduce a shell. In the second part I improved its detection rate using natural code caves and hiding the jump to the cave between the instructions of the program.
In this part I’m going to show you how to avoid that antivirus detect the shell of the code cave through encryption and decryption at runtime. Thanks again to OscarAkaElvis, who taught me these techniques.
Cipher natural code caves
This method is based on the previous method. Some antivirus (only one or two, as far as I know) can detect the previous method by the shell signature. Since the instructions that our payload follows to create the reverse shell were obtained from metasploit using MSFvenom, it would be relatively easy for an antivirus to get the code from that payload and detect it in the scans.
The tactic is as follows: we will use two natural code caves. In one we will make a decryption program, and in the other we will have the shell. The idea is to put an encrypted shell so that in a static analysis (which is what the antivirus does) it can not be detected that makes that code. At the moment that we decide of the course of the program, we jump to a function that when executing decrypts the shell, and later we jump to the shell already decrypted.
As the antivirus does not run the program, the shell is undetectable. Let’s see it step by step.
Let’s start from the file we modified in the second part of this series. If you have any doubt, I recommend you to keep an eye on it. From the previous file, what we do is go to where we jump to the code cave, and put the JMP to the second code cave that detected us cave_miner, in my case to the address 00477857:
In this new code section we write the decryption function. I have chosen the XOR function, since it is bidirectional: if you make the XOR of the shell you get the encrypted shell, and if you make the XOR of the encrypted shell you get the original shell. The code would be as follows:
PUSHAD We save the register values.
PUSHFD We save the register values.
MOV EBX, 00479730 We save in EBX the shell address.
XOR BYTE PTR DS:[EBX], 0E We do XOR of EBX with key “0E”.
INC EBX We increase EBX to pass to the next shell instruction.
CMP EBX, 00479872 We check if we have reached the last shell position.
JNE SHORT 0047785E If we have not reached it, we go back to the XOR instruction.
JMP 00479730 If we have reached it, we jump to the beginning of the shell.
The shellcode part doesn’t change anything, but we have to encrypt it with XOR. For it we have two options, to execute the program once putting a breakpoint before the shell to be able to copy it when the XOR is done, or to look for by means of some online calculator which is the XOR of the hexadecimal code of the shell with “e0” (I have chosen e0 as cipher key, but you can choose any other key that you want).
Regardless of how we do it, we will paste the encrypted shell where the original shell was:
Just remember to encrypt the shell, not what we’ll add later. Also, we don’t put the PUSHAD and PUSHFD from the beginning of the shell, since now we are already doing it in the previous code cave. Finally, we calculate the difference of EBP, that is going to continue being 200, we make the POPFD and POPAD and we execute the instruction that we eliminate to put the jmp:
Then, when you run the program and go to the Help -> About 7-Zip section and press the button that leads to the web, a shell opens in the attacking machine. If we analyze the file with Kaspersky, it doesn’t recognize it as a virus. In addition, the program continues working, and even if you close it, the shell does not close.
This is the definitive version of the backdoor, undetectable for all antivirus programs.