How it works...

Step 1 begins with us launching GDB in TUI mode against the edited binary. This edited version connects to our local machine instead of to the original IP address we discovered during static analysis. In step 2, we set a breakpoint at _start and ran the binary from within GDB. At this point, the registers aren't very interesting to look at since we haven't executed any instructions yet:

The stack isn't very interesting to look at either since we haven't executed any instructions that manipulate the stack. So, instead, we use the instructions in step 3 to see how the registers and stack have been initialized:

As we work through the instructions in step 4, step 5, and step 6, we can see how the affected registers look in terms of their new values to get an idea of what this first block of code is actually accomplishing. The first item that should catch our attention is the syscall instruction, which is telling us that the previous instructions are setting up a system call. Next, we review RAX and see 0x29, which is 41 in decimal. If needed, look this value up in /usr/include/x86_64-linux-gnu/asm/unistd_64.h. You will see that this is the socket system call. So, with RAX holding the socket system call value, RDI holds the int domain value for the first argument, RSI contains the int type argument, and RDX contains the int protocol argument, which happens to be TCP in this case. Review the /etc/protocols file for more information about any protocol values:

In step 7, we look at the stack to see whether it's been affected at all, and it hasn't since we didn't execute any PUSH or POP instructions:

Repeating the same steps, we continue executing each instruction, stopping before the syscall instruction is executed. Looking at the registers, we can see that RAX, RDI, RSI, and RDX are set up for the connect system call. The RAX register contains the value 42, while the RDI register holds the sockfd return value from our socket system call that we previously executed, which in this case is the value 3. The RSI register holds an address to the top of the stack, 0x7fffffffde60, which represents the const struct sockaddr *addr argument, while RDX holds the value 16, which represents the socklen_t addrlen argument:

Next, we examine the stack with the instructions in the last part of step 10. This gives us insight into what the RSI register points to. One technique that binary authors use to avoid the use of NULL characters in a program written in assembly is to find creative ways to manipulate the stack.

In the following disassembled code, we can see that the MOV instructions are copying values onto the stack and that a SUB instruction is used to adjust the stack pointer. As we discovered in the static analysis phase, the instructions between 0x40009f <_start+31> and 0x4000b7 <_start+55> inclusive are using this technique to set up the stack with the IP address, port, and protocol in order to fulfill the second argument to the connect system call. In this case, the protocol that's being used is IP as opposed to TCP. If we were to rewrite this program, we could've easily removed the instruction at 0x4000b2 <_start+50>, making the protocol TCP instead of IP:

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

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