Today, we will be looking at Metasploit’s linux/x86/read_file payload. In this post, we will uncover how this payload works internally when it tries to read the /etc/passwd file. We will use GDB-Peda for our analysis. Using msfvenom, i created a file, i.e., read. Elf and while i was generating the file i used PATH value as /etc/passwd.
Therefore, when the file is made to execute, it will read the contents of the /etc/passwd and will display it on the screen as shown in the following image:
Let’s load this file into GDB-Peda, set a breakpoint on the shellcode(using *&shellcode) and run the program.We are presented with the following screen:
We can see that the very first instruction is a Jump statement. Taking the jump, we have the following instruction:
Taking the call instruction, we are presented with the following screen:
Looks like we finally arrived at the shellcode and the previous two statements were nothing but a JUMP-CALL sequence which would have pushed the hardcoded file path onto the stack. We can see that the stack contains /etc/passwd which is the path we defined in the shellcode. Nevertheless, the first instruction is to move 0x5 to EAX register. The 0x5 value denotes sys_open system call which follows the following format:
open(const char **pathname*, int *flags*);
The open call requires *pathname in the EBX register. So, the next instruction in the shellcode, which is, pop ebx not only completes the JUMP-CALL-POP sequence but sets the open system call perfectly. In the next instruction, ECX gets cleared out and now have a value 0 in it. A successful open should return the file descriptor in EAX register. Let’s see:
We can see the descriptor in EAX. The next statement moves the descriptor to EBX. Next, EAX is loaded with 0x3 which is sys_read system call:
ssize_t read(int fd, void *buf, size_t count);
We can see that to setup read system call. EBX should be loaded with fd which is the file descriptor. However, EBX has already been set up using the previous instruction. The next instruction is to move the top of the stack to EDI, and in the next instruction, it is transferred to ECX which is the register to be set up for *buf. Finally, move 0x1000 to EDX will move 0x1000 as the count. Let’s see the next segment:
Next instruction will issue the interrupt for the read system call. In the next one, the result from EAX is moved to EDX. Next, 0x4 is moved to EAX which is nothing but syscall number for write system call. The value 0x1 is moved to EBX which means that the output will be written to console.The ECX register is unaffected by the previous call and is not required to be set up again. Hence, the interrupt is issued:
In the final segment of the code, The value 0x1 is moved to EAX which denotes an exit call. Additionally, 0x0 is moved to EBX as the error_code and interrupt is issued which will terminate the program.
We saw that the shellcode works by opening the file using open call, reading it using read call and outputting the data onto the console using write system call and finally making an exit using the exit system call. Pretty Straightforward.