How it works...

In steps 1 and 2, we execute the nexti instruction right before the next syscall instruction is executed. The RAX register contains the value 59, which is the execve system call according to /usr/include/x86_64-linux-gnu/asm/unistd_64.h. The execve system call requires three arguments. RDI holds an address to a location on the stack for the const char *filename argument, RSI also holds an address pointing to a location on the stack for char *const argv[], and RDX holds the value 0x0 for the final argument, char *const envp[]:

In the last part of step 3, we issue two different GDB commands to examine the stack. The first command tells GDB that we want to look at 16 entries on the stack in hexadecimal format. RDI holds the 0x7fffffffde48 address, which is an address that points to the 0x2f2f2f2f2f62696e and 0x2f2f2f2f62617368 values on the stack. How did we figure that out? Look at the line that shows the 0x7fffffffde46 address. The first value is 0x2f2f0000. Convert it from Little Endian to get 0x00002f2f and then skip the first two bytes of that value to get 0x2f2f, which is hexadecimal for //. That's the start of the value that's stored at memory address 0x7fffffffde48.

Continue adding on the values you see following 0x2f2f until you hit a NULL byte and you're left with 0x2f2f2f2f2f62696e 0x2f2f2f2f62617368. So, RDI points to 0x2f2f2f2f2f62696e 0x2f2f2f2f62617368. When converted from hexadecimal, we get the /////bin and ////bash strings, respectively. The RSI register holds the address of the top of the stack, which contains two addresses as its first two values. Using the same process we just used for RDI, we combine the first two values at the top of the stack, stopping at the first NULL byte to get the address 0x7fffffffde48, and the second address 0x7fffffffde3e, stopping at the second NULL byte.

We know that the first address points to /////bin////bash already. We can use the same process to figure out the second address, but instead, we'll rely on the second command in step 3 for help:

The second command in step 3 displays values on the stack as strings and expands the output to 32. The following screenshot shows us -i on the stack, located at 0x7fffffffde3e:

If we review the second set of output from this command, as instructed in step 4, we'll see that /////bin////bash starts at the 0x7fffffffde48 address, just like we calculated previously:

How does all of this work in the context of the system call? Recall that the execve system call requires three arguments, all of which require a pointer as a value. Essentially, we provide an address that points to the proper values for these arguments—well, except for the third argument since we're not passing any environment variables. In that case, a NULL byte is passed as the final argument to the system call. The stack provides a means by which the program can accomplish this pointer magic in order to set the system call up correctly.

Step 5 finishes with executing the final syscall instruction and /bin/bash -i and then passes control to /bin/bash. Examining the Terminal tab running netcat should present you with a Bash prompt, as instructed in the last part of step 5. Steps 6 through 8 in this recipe exit Bash and GDB.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.228.95